Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
500c8b1
feat(notifications): record the last push registration per account
bmc08gt Oct 28, 2026
06f5030
feat(notifications): create every channel at app start
bmc08gt Oct 28, 2026
ec9127c
feat(notifications): status model and support report
bmc08gt Oct 28, 2026
c4864e7
feat(theme): add warningText colour token
bmc08gt Oct 28, 2026
df211bd
feat(notifications): notification status page in Settings
bmc08gt Oct 28, 2026
8ae2608
fix(notifications): label the exempted standby bucket; status page sp…
bmc08gt Oct 28, 2026
5b70a2c
feat(notifications): animate status rows in place and blur scroll edges
bmc08gt Oct 28, 2026
6db73d0
feat(notifications): check again and pull to refresh on the status page
bmc08gt Oct 28, 2026
5a7bc71
fix(notifications): keep the summary title on one line beside Check a…
bmc08gt Oct 28, 2026
9730f25
feat(notifications): check again in the top bar; clip card ripples
bmc08gt Oct 28, 2026
074b72b
fix(notifications): say "just now" for a registration confirmed under…
bmc08gt Oct 28, 2026
c0d77a9
fix(notifications): title-case copy, toast on test sent, steady rows
bmc08gt Oct 28, 2026
e046272
fix(notification-status): drop the glass on in-flow actions at large …
bmc08gt Oct 28, 2026
4bc110e
feat(notification-status): show a check-circle on the test sent toast
bmc08gt Oct 28, 2026
9a6b602
fix(push): time out every AddToken call site and keep the last ok time
bmc08gt Oct 28, 2026
04482d3
fix(notification-status): match the settled spec for summary, rows an…
bmc08gt Oct 28, 2026
682ddcb
fix(push): save no record when the timeout fires before a token is sent
bmc08gt Oct 28, 2026
7997fdb
fix(notification-status): keep titles and fix pills in place during C…
bmc08gt Oct 28, 2026
3fcfcca
fix(notification-status): report this page's latest run and the last …
bmc08gt Oct 28, 2026
27003dd
feat(notification-status): send the test notification from the server
bmc08gt Oct 29, 2026
d587f39
fix(notification-status): keep the last summary while Check Again runs
bmc08gt Oct 29, 2026
59a7bdf
test(notification-status): pin the held summary for Try Again and Tur…
bmc08gt Oct 29, 2026
d18ea42
fix(notification-status): say where to turn on the Misc. channel
bmc08gt Oct 29, 2026
4106510
fix(notification-status): read a cancelled test push as unreachable
bmc08gt Oct 29, 2026
7bcec1b
fix(notification-status): title-case check names and call the fallbac…
bmc08gt Oct 29, 2026
1a7209a
fix(notification-status): post the test push on a high-importance cha…
bmc08gt Oct 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/flipcash/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ dependencies {
implementation(project(":apps:flipcash:features:menu"))
implementation(project(":apps:flipcash:features:lab"))
implementation(project(":apps:flipcash:features:device-logs"))
implementation(project(":apps:flipcash:features:notification-status"))
implementation(project(":apps:flipcash:features:appupdates"))
implementation(project(":apps:flipcash:features:deposit"))
implementation(project(":apps:flipcash:features:myaccount"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.flipcash.app

import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.app.NotificationManagerCompat
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import coil3.ImageLoader
Expand All @@ -23,6 +24,7 @@ import com.getcode.utils.trace
import dev.bmcreations.phantom.connect.PhantomSdk
import dagger.Lazy
import com.flipcash.app.messenger.LinkPreviewStartup
import com.flipcash.app.notifications.NotificationChannels
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -85,6 +87,7 @@ class FlipcashApp : Application(), Configuration.Provider, SingletonImageLoader.
super.onCreate()
PhantomSdk.init(this)
startupScope.launch {
NotificationChannels.createAll(this@FlipcashApp, NotificationManagerCompat.from(this@FlipcashApp))
authManager.get().init()
eventRepository.get()
preferredCurrencyController.get()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import androidx.navigation3.runtime.NavBackStack
import androidx.navigation3.scene.OverlayScene
import androidx.navigation3.scene.SinglePaneSceneStrategy
import com.flipcash.app.devicelogs.DeviceLogsScreen
import com.flipcash.app.notificationstatus.NotificationStatusScreen
import com.flipcash.app.backupkey.BackupKeyScreen
import com.flipcash.app.balance.WalletScreen
import com.flipcash.app.cash.CashScreen
Expand Down Expand Up @@ -225,6 +226,7 @@ internal fun appEntryProvider(
annotatedEntry<AppRoute.Menu.TrustedWebsites> { TrustedWebsitesScreen() }
annotatedEntry<AppRoute.Menu.BackupKey> { BackupKeyScreen() }
annotatedEntry<AppRoute.Menu.DeviceLogs> { DeviceLogsScreen() }
annotatedEntry<AppRoute.Menu.NotificationStatus> { NotificationStatusScreen() }
annotatedEntry<AppRoute.Menu.AccountSelection> { AccountSelectionScreen() }

annotatedEntry<AppRoute.UserFlags> { UserFlagsScreen() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,8 @@ sealed interface AppRoute : NavKey, Parcelable {
@Serializable
data object DeviceLogs : Menu
@Serializable
data object NotificationStatus : Menu
@Serializable
data object AccountSelection : Menu
@Serializable
data object UserProfile : Menu
Expand Down
87 changes: 87 additions & 0 deletions apps/flipcash/core/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1967,4 +1967,91 @@
<string name="title_selectRecipient">Select Recipient</string>
<string name="title_shareCurrency">Share %1$s</string>
<string name="title_recentChats">Recent Chats</string>
<!-- Notification status (Settings › Advanced › Notifications) -->
<string name="title_notificationStatus">Notifications</string>
<string name="header_notificationStatusPhone">On This Phone</string>
<string name="header_notificationStatusFlipcash">With Flipcash</string>
<string name="title_notificationStatusWorking">Notifications are working</string>
<string name="title_notificationStatusOff">Notifications are off</string>
<string name="title_notificationStatusChecking">Checking…</string>
<plurals name="title_notificationStatusThingsToCheck">
<item quantity="one">%1$d thing to check</item>
<item quantity="other">%1$d things to check</item>
</plurals>
<plurals name="title_notificationStatusThingsToFix">
<item quantity="one">%1$d thing to fix</item>
<item quantity="other">%1$d things to fix</item>
</plurals>
<string name="subtitle_notificationStatusCheckedJustNow">Checked just now</string>
<plurals name="title_notificationStatusChecksPassed">
<item quantity="one">%1$d check passed</item>
<item quantity="other">%1$d checks passed</item>
</plurals>
<string name="action_sendTestNotification">Send Test Notification</string>
<string name="action_sendTestNotificationAgain">Send Again</string>
<string name="action_shareReport">Share Report</string>
<string name="action_turnOn">Turn On</string>
<string name="action_fix">Fix</string>
<string name="action_tryAgain">Try Again</string>
<string name="action_checkAgain">Check Again</string>
<string name="description_notificationStatusFooter">Flipcash sends the test to every phone signed in to this account.</string>
<string name="description_notificationStatusTestDisabled">Turn on notifications to send a test.</string>
<string name="description_notificationStatusTestDisabledChannelOff">Turn on %1$s in Android settings to send a test.</string>
<string name="toast_notificationStatusTestSent">Test notification sent</string>
<string name="toast_notificationStatusTestUnreachable">Couldn\'t reach Flipcash</string>
<string name="toast_notificationStatusTestFailed">Couldn\'t send a test notification</string>

<string name="title_notificationCheckAllowed">Notifications Allowed</string>
<string name="subtitle_notificationCheckAllowed">Allowed in Android settings</string>
<string name="title_notificationCheckNotAllowed">Notifications are turned off</string>
<string name="subtitle_notificationCheckNotAllowed">Turned off for Flipcash in Android settings</string>
<string name="title_notificationCheckChatOff">Chat notifications are off</string>
<string name="subtitle_notificationCheckChatOff">Messages and replies won\'t show</string>
<string name="title_notificationCheckDepositsOff">Deposit notifications are off</string>
<string name="subtitle_notificationCheckDepositsOff">Deposits and withdrawals won\'t show</string>
<string name="title_notificationCheckBuySellOff">Buy and sell notifications are off</string>
<string name="subtitle_notificationCheckBuySellOff">Purchases and sales won\'t show</string>
<string name="title_notificationCheckGainOff">Price alerts are off</string>
<string name="subtitle_notificationCheckGainOff">Price moves won\'t show</string>
<string name="title_notificationCheckContactsOff">Contact notifications are off</string>
<string name="subtitle_notificationCheckContactsOff">You won\'t hear when contacts join</string>
<string name="title_notificationCheckGeneralOff">Misc. notifications are off</string>
<string name="subtitle_notificationCheckGeneralOff">Other updates from Flipcash won\'t show</string>
<string name="title_notificationCheckOtherCategories">Other Categories</string>
<!-- %1$s is a list like "Payments, gains and contacts" -->
<string name="subtitle_notificationCheckOtherCategories">%1$s are on</string>
<string name="label_notificationCategoryChat">chat</string>
<string name="label_notificationCategoryPayments">payments</string>
<string name="label_notificationCategoryGains">gains</string>
<string name="label_notificationCategoryContacts">contacts</string>
<string name="label_notificationCategoryGeneral">general updates</string>
<!-- Joins the last two items of a list -->
<string name="label_listAnd">%1$s and %2$s</string>
<string name="title_notificationCheckBattery">Battery Optimization</string>
<string name="subtitle_notificationCheckBattery">Flipcash is not optimized</string>
<string name="title_notificationCheckBatteryOn">Battery optimization is on</string>
<string name="subtitle_notificationCheckBatteryOn">Android may delay notifications</string>
<string name="title_notificationCheckBackground">Background Activity</string>
<!-- %1$s is a standby bucket, e.g. "Active" -->
<string name="subtitle_notificationCheckBackground">Not restricted · standby: %1$s</string>
<string name="subtitle_notificationCheckBackgroundLimited">Android is limiting Flipcash in the background</string>
<string name="title_notificationCheckBackgroundRestricted">Background activity is restricted</string>
<string name="subtitle_notificationCheckBackgroundRestricted">Notifications may not arrive</string>
<string name="title_notificationCheckPlayServices">Google Play Services</string>
<string name="subtitle_notificationCheckPlayServices">Available</string>
<string name="subtitle_notificationCheckPlayServicesUpdate">Google Play services needs an update</string>
<string name="title_notificationCheckPlayServicesMissing">Google Play services isn\'t available</string>
<string name="subtitle_notificationCheckPlayServicesMissing">Push notifications need it</string>
<string name="title_notificationCheckRegistered">Registered for Push</string>
<string name="title_notificationCheckRegistering">Checking registration…</string>
<string name="subtitle_notificationCheckRegistering">Contacting Flipcash</string>
<string name="subtitle_notificationCheckRegistered">Confirmed just now</string>
<string name="title_notificationCheckNoToken">Couldn\'t get a push token from Google</string>
<string name="title_notificationCheckTokenRejected">Flipcash rejected this phone\'s push token</string>
<string name="title_notificationCheckUnreachable">Couldn\'t reach Flipcash</string>
<string name="subtitle_notificationCheckUnreachable">Check your connection</string>
<!-- %1$s is a relative time, e.g. "2 hours ago" -->
<string name="subtitle_notificationCheckLastConfirmed">Last confirmed %1$s</string>
<string name="subtitle_notificationCheckLastConfirmedJustNow">Last confirmed just now</string>
<string name="title_notificationCheckFailed">Registration failed</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.material.icons.filled.Science
import androidx.compose.material.icons.outlined.Block
import androidx.compose.material.icons.outlined.Description
import androidx.compose.material.icons.outlined.Language
import androidx.compose.material.icons.outlined.Notifications
import androidx.compose.material.icons.outlined.Palette
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.painter.Painter
Expand Down Expand Up @@ -74,6 +75,15 @@ internal data object DeviceLogs : FullMenuItem<SettingsViewModel.Event>() {
override val action: SettingsViewModel.Event = SettingsViewModel.Event.OpenScreen(AppRoute.Menu.DeviceLogs)
}

internal data object NotificationStatus : FullMenuItem<SettingsViewModel.Event>() {
override val icon: Painter
@Composable get() = rememberVectorPainter(Icons.Outlined.Notifications)
override val name: String
@Composable get() = stringResource(CoreR.string.title_notificationStatus)
override val action: SettingsViewModel.Event =
SettingsViewModel.Event.OpenScreen(AppRoute.Menu.NotificationStatus)
}

internal data object BetaFlags : FullMenuItem<SettingsViewModel.Event>() {
override val icon: Painter
@Composable get() = rememberVectorPainter(Icons.Filled.Science)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ internal class SettingsViewModel @Inject constructor(
SettingsSection(R.string.title_settingsSectionPrivacy, listOf(Blocklist, TrustedWebsites)),
SettingsSection(
R.string.title_advancedFeatures,
listOf(/* BillCustomizer, */ DeviceLogs, BetaFlags, SwitchAccount),
listOf(/* BillCustomizer, */ DeviceLogs, NotificationStatus, BetaFlags, SwitchAccount),
),
SettingsSection(
R.string.title_settingsSectionAccount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.flipcash.app.myaccount.internal.settings.BetaFlags
import com.flipcash.app.myaccount.internal.settings.Blocklist
import com.flipcash.app.myaccount.internal.settings.DeleteAccount
import com.flipcash.app.myaccount.internal.settings.DeviceLogs
import com.flipcash.app.myaccount.internal.settings.NotificationStatus
import com.flipcash.app.myaccount.internal.settings.LogOut
import com.flipcash.app.myaccount.internal.settings.RequireBiometrics
import com.flipcash.app.myaccount.internal.settings.SettingsViewModel
Expand Down Expand Up @@ -76,7 +77,7 @@ class SettingsViewModelTest {
listOf(
AccessKey, RequireBiometrics,
Blocklist, TrustedWebsites,
DeviceLogs, BetaFlags,
DeviceLogs, NotificationStatus, BetaFlags,
LogOut, DeleteAccount,
),
state.items(),
Expand Down
2 changes: 2 additions & 0 deletions apps/flipcash/features/notification-status/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build/
.gradle/
22 changes: 22 additions & 0 deletions apps/flipcash/features/notification-status/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
plugins {
alias(libs.plugins.flipcash.android.feature)
}

android {
namespace = "${Gradle.flipcashNamespace}.features.notificationstatus"
}

dependencies {
implementation(project(":apps:flipcash:shared:authentication"))
implementation(project(":apps:flipcash:shared:notifications"))
implementation(project(":libs:logging"))
implementation(project(":services:flipcash"))
implementation(libs.play.services.base)
implementation(libs.bundles.haze)

testImplementation(kotlin("test"))
testImplementation(libs.bundles.unit.testing)
testImplementation(libs.grpc.stub)
testImplementation(testFixtures(project(":libs:coroutines")))
testImplementation(project(":apps:flipcash:shared:push"))
}
Loading
Loading