# shinyMobile Tools

## Mobile preview

Since V0.2.0, `{shinyMobile}` has a function to preview your app in a large range of mobile devices: iphone X, iphone 8+, iphone8, iphone 5s, iphone 4s, ipad, Samsung galaxy S5, Samsung galaxy Note 8, … either locally on online:

    library(shiny)
    library(shinyMobile)
    preview_mobile(appPath = system.file("examples/gallery/app.R", package = "shinyMobile"), device = "iphoneX")
    preview_mobile(url = "https://dgranjon.shinyapps.io/miniUI2DemoMd", device = "ipadMini")

The local preview is a 4 steps process:

- run `preview_mobile` with appPath
- Copy the returned code `R -e "shiny::runApp('appPath', port = 3838)"` in a terminal to launch the app
- Press enter to run the wrapper app
- Have fun!

`preview_mobile` has other options such as color and landscape (to preview in landscape mode).

## Pull to Refresh

`{shinyMobile}` introduces the pull to refresh feature. It may be used to refresh the page content by pulling from top to bottom. This feature is disabled by default but passing `pullToRefresh = TRUE` in `f7Page` options will activate it. On the server side, an input, namely input$ptr is TRUE when ptr is refreshed and becomes NULL at the end of the animation. This allows to trigger updates/computations on the server side, for instance:

    shinyApp(
      ui = f7Page(
        title = "My app",
        options = list(pullToRefresh = TRUE),
        f7SingleLayout(
          navbar = f7Navbar(
            title = "Single Layout",
            hairline = FALSE,
            shadow = TRUE
          ),
          toolbar = f7Toolbar(
            position = "bottom",
            f7Link(label = "Link 1", href = "https://www.google.com"),
            f7Link(label = "Link 2", href = "https://www.google.com")
          ),
          # main content
          f7List(
            lapply(1:3, function(j) {
              f7ListItem(
                letters[j],
                media = f7Icon("alarm_fill"),
                right = "Right Text",
                header = "Header",
                footer = "Footer"
              )
            })
          )
        )
      ),
      server = function(input, output, session) {
        observe(print(input$ptr))

        observeEvent(input$ptr, {
          ptrStatus <- if (input$ptr) "on"
          f7Dialog(
            text = paste('ptr is', ptrStatus),
            type = "alert"
          )
        })
      }
    )

## Predefined input values

`{shinyMobile}` contains a set of useful functions to help you setting the layout as best as possible.

### Informations about your current device

#### Description

`{shinyMobile}` has a predefined input, namely input$deviceInfo:

    shiny::shinyApp(
      ui = f7Page(
        title = "My app",
        f7SingleLayout(
          navbar = f7Navbar(
            title = "Access device info",
            hairline = FALSE,
            shadow = TRUE
          ),
          # main content
          verbatimTextOutput("info")
        )
      ),
      server = function(input, output) {
        output$info <- renderPrint({
          input$deviceInfo
        })
      }
    )

The following fields are returned:

- `input$deviceInfo$os`, returns a string containing your OS
- `input$deviceInfo$desktop`, TRUE or FALSE (if you are running the app on your laptop or desktop)
- `input$deviceInfo$standalone`, TRUE or FALSE (standalone, namely whether you access the app like a native app)
- `input$deviceInfo$webview`, TRUE or FALSE (webview)
- `input$deviceInfo$electron`, TRUE or FALSE (electron)

There are other fields, with less inportance:

- `input$deviceInfo$ios`, TRUE or FALSE (if you are running under iOS)
- `input$deviceInfo$android`, TRUE or FALSE (if you are running under android)
- `input$deviceInfo$androidChrome`, TRUE or FALSE (if you are running under android with Chrome)
- `input$deviceInfo$iphone`, TRUE or FALSE (if you have an iphone)
- `input$deviceInfo$ipod`, TRUE or FALSE (if you have an ipod)
- `input$deviceInfo$ipad`, TRUE or FALSE (if you have an ipad)
- `input$deviceInfo$edge`, TRUE or FALSE (if you are using edge)
- `input$deviceInfo$ie`, TRUE or FALSE (if you are using Internet Explorer)
- `input$deviceInfo$firefox`, TRUE or FALSE (if you are using Firefox)
- `input$deviceInfo$macos`, TRUE or FALSE (if you have macOS)
- `input$deviceInfo$windows`, TRUE or FALSE (if you have Windows)
- `input$deviceInfo$cordova`, TRUE or FALSE (cordova)
- `input$deviceInfo$phonegap`, TRUE or FALSE (phonegap)

#### Usecase

Below the example displays a card only when the app is on desktop.

    shinyApp(
      ui = f7Page(
        title = "My app",
        f7SingleLayout(
          navbar = f7Navbar(
            title = "Access device info",
            hairline = FALSE,
            shadow = TRUE
          ),
          # main content
          uiOutput("card"),
          textOutput("userAgent"),
        )
      ),
      server = function(input, output) {

        output$userAgent <- renderText(input$deviceInfo$desktop)

        # generate a card only for desktop
        output$card <- renderUI({
          if (input$deviceInfo$desktop) {
            f7Card(
              "This is a simple card with plain text,
              but cards can also contain their own header,
              footer, list view, image, or any other element."
            )
          }
        })
      }
    )

### Informations about Shiny inputs

`{shinyMobile}` has `input$lastInputChanged` which returns the name, value and type of the last changed input, see below:

    shinyApp(
      ui = f7Page(
        title = "My app",
        f7SingleLayout(
          navbar = f7Navbar(
            title = "Single Layout",
            hairline = FALSE,
            shadow = TRUE
          ),
          toolbar = f7Toolbar(
            position = "bottom",
            f7Link(label = "Link 1", href = "https://www.google.com"),
            f7Link(label = "Link 2", href = "https://www.google.com")
          ),
          # main content
          f7Card(verbatimTextOutput("infos")),
          f7Card(
            f7Text(inputId = "text", label = "Text"),
            f7Slider(inputId = "range1", label = "Range", min = 0, max = 2, value = 1, step = 0.1),
            f7Stepper(inputId = "stepper1", label = "Stepper", min = 0, max = 10, value = 5),
            verbatimTextOutput("lastChanged")
          )
        )
      ),
      server = function(input, output) {
        output$infos <- renderPrint(input$shinyInfo)
        output$lastChanged <- renderPrint(input$lastInputChanged)
      }
    )

This is convenient since usually, there is no shortcut to get the last changed value and this needs to be done server side in shiny.

Soon there will be a way to compare initial input values (frozen) to current input values and get a diff.

### Other information

`input$shinyInfo` gives the current workerId (for shinyapps.io, shiny server pro, rstudio connect), the unique sessionId (equal to session$token on the server side).