---
title: "Disconnected, Reconnect and Reload"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Disconnected, Reconnect and Reload}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, echo=FALSE, message=FALSE}
library(bslib)
```

## Custom disconnected screen

Nobody likes it when an app stops responding. Traditionally, Shiny apps will be "grayed out". Since this doesn't provide a nice user experience, `{shinyMobile}` adds a custom disconnected screen. This screen (a toast) is displayed when the app is disconnected from the server.

<div class="text-center mt-4">
<a class="btn btn-primary" data-bs-toggle="collapse" href="#reconnect" role="button" aria-expanded="false" aria-controls="singleLayout">
Code
</a>
</div>

<div class="collapse" id="reconnect">
```{r, eval = FALSE}
library(shiny)
library(shinyMobile)

shinyApp(
  ui = f7Page(
    options = list(dark = FALSE),
    title = "My app",
    f7SingleLayout(
      navbar = f7Navbar(
        title = "Custom disconnected screen",
        hairline = FALSE
      ),
      f7List(
        inset = TRUE,
        dividers = FALSE,
        strong = TRUE,
        f7Text(
          inputId = "text",
          label = "Text input",
          value = "Some text",
          placeholder = "Your text here"
        ),
        f7Select(
            inputId = "select",
            label = "Make a choice",
            choices = 1:3,
            selected = 1
          )
      ),
      f7Block(
        f7Button(inputId = "disconnect",
                 label = "Disconnect me")
      ),
      f7Block(
        verbatimTextOutput("mytext"),
        verbatimTextOutput("myselect")
      )
    )
  ),
  server = function(input, output) {
    # set ignoreInit to avoid the observer being triggered after reconnect
    # this happens because of restoring the app's state
    observeEvent(input$disconnect, ignoreInit = TRUE, {
      print(input$disconnect)
      stop("Oops, I disconnected you!")
    })
    
    output$mytext <- renderText({
      input$text
    })
    
    output$myselect <- renderText({
      input$select
    })
  }
)
```
</div>

The user is given two options: either to **reconnect** or to **reload** the app. There's a subtle difference between the two, which is explained below.

## Reconnect

This button will attempt to reconnect to the server. If the server is not available, or encounters an error again, the custom disconnected screen will be displayed again.

<br>

When reconnecting, Shiny attempts to restore the app to its previous state. This means that the app will be in the same state as before the disconnection. In the above code, this means `input$disconnect`, `input$text` and `input$select` will be restored to their previous values. The user actually doesn't see that they are "restored": it looks like the user never left. But it is important to realize that behind the scenes, Shiny is starting from the initial state of your app and sets back the values of the inputs to their previous values. This means observers and reactive expressions will be triggered again. In the code above, we're using `ignoreInit` to avoid the observer being triggered after reconnect. If we would omit this, we would end up being disconnected again. After all, the value of `input$disconnect` changes from `0` to `1` when clicked.

<br>

Note that the JS code behind the reconnect button ignores the user [reconnect setup](https://shiny.rstudio.com/articles/reconnecting.html) and proposes reconnecting regardless of the `session$allowReconnect` configuration. A solution is provided in the [Outstanding User Interfaces with Shiny](https://unleash-shiny.rinterface.com/mobile-going-further#enhance-the-disconnect-screen) book.

## Reload

The custom disconnected screen also includes a reload button. This button will reload the app (like hitting refresh in your browser). This is useful when the app is stuck in a loop and the reconnect button doesn't work. Compared to reconnecting, reloading will start from a clean slate: there's no restoring of values.

<br>

Note that when setting your app up to be a PWA, there's an `offline.html` asset generated when using `charpente::set_pwa()`. This page will be displayed when the user is offline. This page contains a reload button that will reload the app. It is not reconnecting.
