Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MOB-421 add settings control to turn in-app notifications on/off completely #49

Merged
merged 4 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions v4/app/src/main/assets/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@
"field":"v4_theme"
}
},
{
"title" : {
"text" : "APP.V4.NOTIFICATIONS"
},
"link" : {
"text" : "settings/notifications"
},
"field":{
"field":"should_display_in_app_notifications"
}
},
{
"title" : {
"text" : "APP.V4.DIRECTION_COLOR_PREFERENCE"
Expand Down
11 changes: 11 additions & 0 deletions v4/app/src/main/assets/settings_debug.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@
"field":"v4_theme"
}
},
{
"title" : {
"text" : "APP.V4.NOTIFICATIONS"
},
"link" : {
"text" : "settings/notifications"
},
"field":{
"field":"should_display_in_app_notifications"
}
},
{
"title" : {
"text" : "APP.V4.DIRECTION_COLOR_PREFERENCE"
Expand Down
45 changes: 13 additions & 32 deletions v4/app/src/main/assets/settings_notifications.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,22 @@
"fields":[
{
"title":{
"text":"General"
},
"subtitle":{
"text":"New markets, newsletters, product updates, and more."
},
"field":{
"field":"notifications_general",
"optional":true,
"type" : "bool"
}
},
{
"title":{
"text":"Account"
},
"subtitle":{
"text":"Deposits, withdrawals, and other important account changes."
},
"field":{
"field":"notifications_account",
"optional":true,
"type" : "bool"
}
},
{
"title":{
"text":"Trading"
},
"subtitle":{
"text":"Order updates, liquidation warnings, funding payments."
"text":"APP.V4.DISPLAY_IN_APP_NOTIFICATIONS"
},
"field":{
"field":"notifications_account",
"field":"should_display_in_app_notifications",
"type":"bool",
"optional":true,
"type" : "bool"
"options" : [
{
"text": "yes",
"value" : "1"
},
{
"text": "no",
"value" : "0"
}
]
}
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ object ProfileRoutes {
const val rewards = "rewards"
const val debug_enable = "action/debug/enable"
const val report_issue = "settings/report_issue"
const val notifications = "settings/notifications"
}

object NewsAlertsRoutes {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import exchange.dydx.trading.integration.analytics.CompositeTracking
import exchange.dydx.trading.integration.analytics.Tracking
import exchange.dydx.trading.integration.cosmos.CosmosV4WebviewClientProtocol
import exchange.dydx.utilities.utils.CachedFileLoader
import exchange.dydx.utilities.utils.SharedPreferencesStore
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
Expand All @@ -37,6 +38,7 @@ class CoreViewModel @Inject constructor(
private val parser: ParserProtocol,
private val tracker: Tracking,
val compositeTracking: CompositeTracking,
private val preferencesStore: SharedPreferencesStore,
) : ViewModel() {
private var globalWorkers: DydxGlobalWorkers? = null

Expand All @@ -53,6 +55,7 @@ class CoreViewModel @Inject constructor(
formatter = formatter,
parser = parser,
tracker = tracker,
preferencesStore = preferencesStore,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import exchange.dydx.trading.feature.profile.help.DydxHelpView
import exchange.dydx.trading.feature.profile.history.DydxHistoryView
import exchange.dydx.trading.feature.profile.keyexport.DydxKeyExportView
import exchange.dydx.trading.feature.profile.language.DydxLanguageView
import exchange.dydx.trading.feature.profile.notifications.DydxNotificationsView
import exchange.dydx.trading.feature.profile.reportissue.DydxReportIssueView
import exchange.dydx.trading.feature.profile.rewards.DydxRewardsView
import exchange.dydx.trading.feature.profile.settings.DydxSettingsView
Expand Down Expand Up @@ -170,4 +171,12 @@ fun NavGraphBuilder.profileGraph(
) { navBackStackEntry ->
DydxReportIssueView.Content(Modifier)
}

dydxComposable(
router = appRouter,
route = ProfileRoutes.notifications,
deepLinks = appRouter.deeplinks(ProfileRoutes.notifications),
) { navBackStackEntry ->
DydxNotificationsView.Content(Modifier)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package exchange.dydx.trading.feature.profile.notifications

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
import exchange.dydx.trading.common.component.DydxComponent
import exchange.dydx.trading.common.compose.collectAsStateWithLifecycle
import exchange.dydx.trading.common.theme.DydxThemedPreviewSurface
import exchange.dydx.trading.feature.shared.views.SettingsView

@Preview
@Composable
fun Preview_DydxNotificationsView() {
DydxThemedPreviewSurface {
DydxNotificationsView.Content(Modifier, SettingsView.ViewState.preview)
}
}

object DydxNotificationsView : DydxComponent {
@Composable
override fun Content(modifier: Modifier) {
val viewModel: DydxNotificationsViewModel = hiltViewModel()

val state = viewModel.state.collectAsStateWithLifecycle(initialValue = null).value
Content(modifier, state)
}

@Composable
fun Content(modifier: Modifier, state: SettingsView.ViewState?) {
SettingsView.Content(modifier = modifier, state = state)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package exchange.dydx.trading.feature.profile.notifications

import android.content.Context
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import exchange.dydx.abacus.protocols.LocalizerProtocol
import exchange.dydx.platformui.settings.PlatformUISettings
import exchange.dydx.trading.common.DydxViewModel
import exchange.dydx.trading.common.navigation.DydxRouter
import exchange.dydx.trading.feature.shared.NotificationEnabled
import exchange.dydx.trading.feature.shared.views.SettingsView
import exchange.dydx.utilities.utils.SharedPreferencesStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject

private val settingsFile = "settings_notifications.json"

@HiltViewModel
class DydxNotificationsViewModel @Inject constructor(
private val localizer: LocalizerProtocol,
@ApplicationContext private val appContext: Context,
private val router: DydxRouter,
private val preferencesStore: SharedPreferencesStore,
) : ViewModel(), DydxViewModel {

private val mutableState = MutableStateFlow(createViewState())

val state: Flow<SettingsView.ViewState?> = mutableState

private fun createViewState(): SettingsView.ViewState {
val settings = PlatformUISettings.loadFromAssets(appContext, settingsFile)

var viewState = SettingsView.ViewState.createFrom(
settings = settings,
localizer = localizer,
header = localizer.localize("APP.V4.NOTIFICATIONS"),
backAction = {
router.navigateBack()
},
itemFieldAction = { _, value ->
NotificationEnabled.update(preferencesStore, value)
mutableState.value = createViewState()
},
)

viewState.sections.first().items.first().value = NotificationEnabled.currentValue(preferencesStore)

return viewState
}

companion object {
fun currentValueText(
localizer: LocalizerProtocol,
preferencesStore: SharedPreferencesStore,
): String? {
val notificationsOn = NotificationEnabled.enabled(preferencesStore)
return if (notificationsOn) localizer.localize("APP.HEADER.ON") else localizer.localize("APP.HEADER.OFF")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import exchange.dydx.trading.common.DydxViewModel
import exchange.dydx.trading.common.navigation.DydxRouter
import exchange.dydx.trading.feature.profile.color.DydxDirectionColorPreferenceViewModel
import exchange.dydx.trading.feature.profile.language.DydxLanguageViewModel
import exchange.dydx.trading.feature.profile.notifications.DydxNotificationsViewModel
import exchange.dydx.trading.feature.profile.theme.DydxThemeViewModel
import exchange.dydx.trading.feature.profile.tradingnetwork.DydxTradingNetworkViewModel
import exchange.dydx.trading.feature.shared.PreferenceKeys
import exchange.dydx.trading.feature.shared.views.SettingsView
import exchange.dydx.utilities.utils.DebugEnabled
import exchange.dydx.utilities.utils.SharedPreferencesStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import javax.inject.Inject

@HiltViewModel
Expand All @@ -32,7 +33,7 @@ class DydxSettingsViewModel @Inject constructor(
private val abacusStateManager: AbacusStateManagerProtocol,
) : ViewModel(), DydxViewModel {

val state: Flow<SettingsView.ViewState?> = flowOf(createViewState())
val state: Flow<SettingsView.ViewState?> = preferencesStore.stateUpdatedCount.map { createViewState() }

private fun createViewState(): SettingsView.ViewState {
val settingsFile = if (DebugEnabled.enabled(preferencesStore)) {
Expand Down Expand Up @@ -82,6 +83,12 @@ class DydxSettingsViewModel @Inject constructor(
abacusStateManager = abacusStateManager,
)
}
PreferenceKeys.Notifications -> {
return@createFrom DydxNotificationsViewModel.currentValueText(
localizer = localizer,
preferencesStore = preferencesStore,
)
}
else -> {
return@createFrom ""
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package exchange.dydx.trading.feature.shared
import exchange.dydx.utilities.utils.SharedPreferencesStore

object NotificationEnabled {
fun enabled(preferencesStore: SharedPreferencesStore): Boolean {
return currentValue(preferencesStore) == "1"
}

fun currentValue(preferencesStore: SharedPreferencesStore): String {
return preferencesStore.read(PreferenceKeys.Notifications, defaultValue = "1")
}

fun update(preferencesStore: SharedPreferencesStore, value: String) {
preferencesStore.save(value, PreferenceKeys.Notifications)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ object PreferenceKeys {
const val Theme = "v4_theme"
const val Env = "env"
const val DirectionColor = "direction_color_preference"
const val Notifications = "should_display_in_app_notifications"
}
Loading
Loading