Add I Want To to an Android app

A small library that opens the same feedback panel as the website: the list of ideas, voting, comments, the guided send flow and sign-in by email code. Download one file, add three lines to Gradle, call one function.

How it works

The library shows the panel in a full-screen WebView. It loads the same widget.js as the website from the service host, so every change to the panel reaches your app without a release of yours.

The service accepts API calls only from a registered origin, and an app has none. So the library shows the panel as a page of https://mobile.iwanto.org, an origin the service accepts from apps for every project that has switched Mobile app on: there is nothing to register. The visitor’s session stays in the WebView between launches, as localStorage does on the web.

  • This is a stop-gap, not the final design: the panel is the web one, not native components, and options that are functions on the web (onBeforeSend) have no equivalent. A native SDK is planned.

Download

A ZIP archive with the source of the library, a ready Gradle module (about 10 KB). Version 1.0.0. Requires Android 7.0 (API 24) or newer, Kotlin and Android Gradle Plugin 8 or newer; it declares the INTERNET permission and its own dependencies itself.

  • The source and a runnable demo app are in the repository, folder demo/android.

Connect it to your project

1. Get the project ID and switch the app on

In the console open your project, Widget & install, and copy the project ID. In the same tab turn on Mobile app: it is off by default, and until you do the service refuses the app.

  • If attachments are on, nothing extra is needed for the app: it uploads through the same signed links as the website, as long as the bucket allows https://mobile.iwanto.org in its CORS rule.

2. Add the module to your project

Unzip the archive into the root of your Android project, so that the folder iwanto/ sits next to app/. Then add the two lines below. Nothing else is needed: the module brings its own dependencies. To update the library later, replace the iwanto/ folder with the one from a newer archive.

// settings.gradle.kts
include(":iwanto")

// app/build.gradle.kts
dependencies {
    implementation(project(":iwanto"))
}

3. Open the panel

Call it from anywhere you have a Context, for example a button handler. The panel opens on top of your screen; the close button, or Back, returns to your app.

import org.iwanto.android.IWantTo
import org.iwanto.android.IWantToConfig

val config = IWantToConfig(
    projectId = "YOUR_PROJECT_ID",
)

button.setOnClickListener { IWantTo.open(this, config) }

4. React to what happens (optional)

Set a listener for analytics or to refresh your own screens. Its methods run on the main thread. Set it once, for example in your Activity, and clear it when the Activity goes away.

IWantTo.listener = object : IWantTo.Listener {
    override fun onSubmit(id: String) { analytics.track("item_created", id) }
    override fun onVote(id: String, value: Int?) { /* 1 = agreed, null = withdrawn */ }
    override fun onComment(id: String, feedbackId: String) {}
    override fun onSignIn(email: String) {}
    override fun onOpen() {}
    override fun onClose() {}
}

// when your Activity goes away:
IWantTo.listener = null

Options

Passed in IWantToConfig. They mean the same as the website widget’s options of the same name.

IWantToConfig(
    projectId = "YOUR_PROJECT_ID",
    locale = "uk",
    theme = IWantToTheme.DARK,
    accentColor = "#c2410c",
    user = IWantToUser(email = me.email, name = me.name),
    meta = mapOf("appVersion" to BuildConfig.VERSION_NAME, "plan" to me.plan),
)
projectIdrequiredThe project ID from the console. Required.
appOrigin"https://mobile.iwanto.org"The origin the panel is shown as. Leave the default unless you run an older self-hosted server without the shared app origin; register your own in the console then.
baseUrl"https://iwanto.org"Where the service lives. Change it only for a self-hosted or local server.
localedevice'en' or 'uk'. By default the device language, then the project’s default.
themeIWantToTheme.AUTOIWantToTheme.AUTO follows the device’s light or dark setting; LIGHT and DARK force it.
accentColorprojectButtons, links and active states, as #hex, rgb() or hsl(). Defaults to the project’s accent.
radius"default"'default', 'sharp' or 'round'.
defaultTypenone'idea', 'problem', 'question' or 'praise', preselected in the send flow.
usernoneIWantToUser(email, name). Only prefills the sign-in form: the visitor still confirms the email with a code.
metaemptyStrings, numbers and booleans stored with each item and visible to the team: app version, plan, build. Up to 50 keys.

If something does not work

The panel says it could not load. The project ID is wrong, or Mobile app is switched off for the project (turn it on in Widget & install), or the server is older than the shared app origin. Check the ID in the console, and that baseUrl points at the right server.
A local server over http. Release builds refuse plain http. For a dev server add a network security config that allows it for that host in debug builds only; the demo app shows one. From the emulator the computer’s localhost is 10.0.2.2.
No sign-in email. Sign-in sends a real code to the address; check spam. A local server may print it to its log instead of mailing it.
Minified release builds. The library ships its own keep rules for the JavaScript bridge; no extra setup is needed.