Android
The Android SDK shows your feedback widget in your Android app: in a screen of its own, in a Compose dialog, or in a place of your own, with your user already signed in.
Install#
Add the library to your app's build.gradle.kts, and its Compose artifact if your app uses Compose:
dependencies {
implementation("dev.swingback:swingback-android:0.1.0")
implementation("dev.swingback:swingback-android-compose:0.1.0") // Compose's dialog and view
}It works on Android 7.0 (API 24) and later.
Set it up#
Configure it once, when your app starts, with your portal's address and a way to get the signed-in user's identity token from your server:
class AcmeApp : Application() {
override fun onCreate() {
super.onCreate()
Swingback.configure(this, "https://acme.example.com") {
// Your server signs the token for the user its session names; null when nobody is signed in.
AcmeApi.feedbackToken()
}
}
}The token is asked for each time the widget opens, off the main thread. Your server signs it with your identity
secret, which never goes in your app: Signing in your users has the function.
Return null when nobody is signed in, and throw when the token can't be had.
Show the widget#
In a screen of its own, over your app:
Swingback.open(context)
Swingback.open(context, SwingbackPage.Changelog)In Compose, a dialog the whole window:
var feedback by remember { mutableStateOf(false) }
Button(onClick = { feedback = true }) { Text("Send feedback") }
if (feedback) SwingbackDialog(onDismissRequest = { feedback = false })Or in a place of your own, filling it:
SwingbackWidget(modifier = Modifier.fillMaxSize(), page = SwingbackPage.Roadmap) // Compose
SwingbackView(context).apply { page = SwingbackPage.Roadmap } // viewsA page is SwingbackPage.Feedback (the default), Roadmap, Changelog, New, Post("dark-mode") or
Board("ideas"), by the slug in a post's or a board's address. In the widget's screen and dialog, the back button goes
back in the widget first, then closes.
Its title and its bar#
The screen's title is the portal's word for the widget, in your reader's language. Give your own, or none, or leave the bar out altogether (the back button closes the screen):
Swingback.open(context, SwingbackPage.Changelog, title = SwingbackTitle.Text("What's new"))
Swingback.open(context, showsBar = false)
SwingbackDialog(onDismissRequest = { feedback = false }, title = SwingbackTitle.Hidden)In a place of your own, the widget takes the back button where you ask, back in the widget while it can go back:
SwingbackWidget(handlesBack = true) in Compose, handlesBack = true on a SwingbackView, which also gives
canGoBack and goBack() for a back button you handle yourself.
When your user signs in or out#
lifecycleScope.launch {
Swingback.identify() // another user signed in: a widget on screen asks for a token now
Swingback.logout() // your user signed out: the widget's session ends
}Events#
Swingback.events is a flow of what the widget did: Ready, Identified, SignedOut, Error(code), and Open and
Close for its screen and dialog. An error's code is one of the widget's, or
token_unavailable when your function threw.
lifecycleScope.launch {
Swingback.events.collect { event -> Log.d("Feedback", event.toString()) }
}Good to know#
- The widget keeps its session in your app's web data, across launches.
logout()ends it in a widget on screen now, else first thing in the next one, after a restart too. - Links that leave the widget open in a Custom Tab over your app; a mail or a phone address opens its app.
- The images a post takes come from the system's photo picker: your app asks for no permission.
- The widget follows the device's light or dark look, and the portal's when your workspace chose one.
- Your portal's address is https. Against a local stack over plain http, your app needs a network security config that
lets it reach
localhostand its subdomains.
