From 02d6fa0dbfaddbc14f5975c4784ed9f4af7af755 Mon Sep 17 00:00:00 2001 From: Infi Date: Sun, 23 Apr 2023 06:04:19 +0200 Subject: [PATCH] feat: sparks & settings button location spark Signed-off-by: Infi --- app/build.gradle | 3 + app/src/main/java/chat/revolt/MainActivity.kt | 2 + .../java/chat/revolt/persistence/KVStorage.kt | 10 +++ .../revolt/screens/chat/ChatRouterScreen.kt | 75 +++++++++++++++- .../screens/settings/DebugSettingsScreen.kt | 82 ++++++++++++++++++ .../revolt/screens/settings/SettingsScreen.kt | 23 ++++- .../res/raw/open_settings_tutorial.lottie | Bin 0 -> 1647 bytes app/src/main/res/values/strings.xml | 5 ++ 8 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/chat/revolt/screens/settings/DebugSettingsScreen.kt create mode 100644 app/src/main/res/raw/open_settings_tutorial.lottie diff --git a/app/build.gradle b/app/build.gradle index a6360534..4286475e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -156,6 +156,9 @@ dependencies { // AboutLibraries - automated OSS library attribution implementation "com.mikepenz:aboutlibraries-compose:$aboutlibraries_version" + // Lottie - animated vector graphics + implementation "com.airbnb.android:lottie-compose:6.0.0" + // Sentry - crash reporting implementation 'io.sentry:sentry-android:6.15.0' implementation 'io.sentry:sentry-compose-android:6.15.0' diff --git a/app/src/main/java/chat/revolt/MainActivity.kt b/app/src/main/java/chat/revolt/MainActivity.kt index 43369d82..d6eec214 100644 --- a/app/src/main/java/chat/revolt/MainActivity.kt +++ b/app/src/main/java/chat/revolt/MainActivity.kt @@ -26,6 +26,7 @@ import chat.revolt.screens.login.GreeterScreen import chat.revolt.screens.login.LoginScreen import chat.revolt.screens.login.MfaScreen import chat.revolt.screens.settings.AppearanceSettingsScreen +import chat.revolt.screens.settings.DebugSettingsScreen import chat.revolt.screens.settings.SettingsScreen import chat.revolt.ui.theme.RevoltTheme import com.google.accompanist.navigation.animation.AnimatedNavHost @@ -111,6 +112,7 @@ fun AppEntrypoint() { composable("settings") { SettingsScreen(navController) } composable("settings/appearance") { AppearanceSettingsScreen(navController) } + composable("settings/debug") { DebugSettingsScreen(navController) } dialog("settings/feedback") { FeedbackDialog(navController) } composable("about") { AboutScreen(navController) } diff --git a/app/src/main/java/chat/revolt/persistence/KVStorage.kt b/app/src/main/java/chat/revolt/persistence/KVStorage.kt index a72b361e..81277345 100644 --- a/app/src/main/java/chat/revolt/persistence/KVStorage.kt +++ b/app/src/main/java/chat/revolt/persistence/KVStorage.kt @@ -29,6 +29,16 @@ class KVStorage @Inject constructor( return dataStore.data.firstOrNull()?.get(stringPreferencesKey(key)) } + suspend fun set(key: String, value: Boolean) { + dataStore.edit { preferences -> + preferences[stringPreferencesKey(key)] = value.toString() + } + } + + suspend fun getBoolean(key: String): Boolean? { + return dataStore.data.firstOrNull()?.get(stringPreferencesKey(key))?.toBoolean() + } + suspend fun remove(key: String) { dataStore.edit { preferences -> preferences.remove(stringPreferencesKey(key)) diff --git a/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt b/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt index 746adc9c..df9e0d7e 100644 --- a/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt +++ b/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -16,13 +17,17 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add +import androidx.compose.material3.AlertDialog import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment @@ -64,6 +69,11 @@ import chat.revolt.screens.chat.sheets.StatusSheet import chat.revolt.screens.chat.views.HomeScreen import chat.revolt.screens.chat.views.NoCurrentChannelScreen import chat.revolt.screens.chat.views.channel.ChannelScreen +import com.airbnb.lottie.RenderMode +import com.airbnb.lottie.compose.LottieAnimation +import com.airbnb.lottie.compose.LottieCompositionSpec +import com.airbnb.lottie.compose.animateLottieCompositionAsState +import com.airbnb.lottie.compose.rememberLottieComposition import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi import com.google.accompanist.navigation.material.ModalBottomSheetLayout import com.google.accompanist.navigation.material.bottomSheet @@ -85,10 +95,19 @@ class ChatRouterViewModel @Inject constructor( val currentChannel: String? get() = _currentChannel.value + private var _sidebarSparkDisplayed = mutableStateOf(true) + val sidebarSparkDisplayed: Boolean + get() = _sidebarSparkDisplayed.value + init { viewModelScope.launch { _currentServer.value = kvStorage.get("currentServer") ?: "home" _currentChannel.value = kvStorage.get("currentChannel") + _sidebarSparkDisplayed.value = if (kvStorage.getBoolean("sidebarSpark") == null) { + false + } else { + kvStorage.getBoolean("sidebarSpark")!! + } } } @@ -108,6 +127,10 @@ class ChatRouterViewModel @Inject constructor( } } + suspend fun setSettingsHintDisplayed() { + kvStorage.set("sidebarSpark", true) + } + fun navigateToServer(serverId: String, navController: NavController) { if (serverId == "home") { navController.navigate("home") { @@ -155,6 +178,12 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = hil val bottomSheetNavigator = rememberBottomSheetNavigator() val navController = rememberNavController(bottomSheetNavigator) + val showSidebarSpark = remember { mutableStateOf(false) } + val sidebarSparkComposition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.open_settings_tutorial)) + val sidebarSparkProgress by animateLottieCompositionAsState( + composition = sidebarSparkComposition, + ) + LaunchedEffect(drawerState) { snapshotFlow { drawerState.currentValue } .distinctUntilChanged() @@ -175,11 +204,52 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = hil } } + LaunchedEffect(viewModel.sidebarSparkDisplayed) { + snapshotFlow { viewModel.sidebarSparkDisplayed } + .distinctUntilChanged() + .collect { displayed -> + showSidebarSpark.value = !displayed + } + } + ModalBottomSheetLayout( sheetShape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), sheetBackgroundColor = MaterialTheme.colorScheme.surface, bottomSheetNavigator = bottomSheetNavigator, ) { + if (showSidebarSpark.value) { + AlertDialog( + onDismissRequest = {}, + title = { + Text(stringResource(id = R.string.spark_sidebar_settings_tutorial)) + }, + text = { + Column { + LottieAnimation( + composition = sidebarSparkComposition, + progress = { sidebarSparkProgress }, + modifier = Modifier + .fillMaxWidth() + .aspectRatio(1f), + renderMode = RenderMode.HARDWARE + ) + Text(stringResource(id = R.string.spark_sidebar_settings_tutorial_description_1)) + Text(stringResource(id = R.string.spark_sidebar_settings_tutorial_description_2)) + } + }, + confirmButton = { + TextButton(onClick = { + scope.launch { + viewModel.setSettingsHintDisplayed() + } + showSidebarSpark.value = false + }) { + Text(stringResource(id = R.string.spark_sidebar_settings_tutorial_acknowledge)) + } + } + ) + } + Column { AnimatedVisibility(visible = RealtimeSocket.disconnectionState != DisconnectionState.Connected) { DisconnectedNotice( @@ -255,7 +325,10 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = hil } } - Crossfade(targetState = viewModel.currentServer) { + Crossfade( + targetState = viewModel.currentServer, + label = "Channel List" + ) { ChannelList( serverId = it, drawerState = drawerState, diff --git a/app/src/main/java/chat/revolt/screens/settings/DebugSettingsScreen.kt b/app/src/main/java/chat/revolt/screens/settings/DebugSettingsScreen.kt new file mode 100644 index 00000000..4757ab17 --- /dev/null +++ b/app/src/main/java/chat/revolt/screens/settings/DebugSettingsScreen.kt @@ -0,0 +1,82 @@ +package chat.revolt.screens.settings + +import androidx.compose.foundation.horizontalScroll +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ElevatedButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.navigation.NavController +import chat.revolt.components.generic.PageHeader +import chat.revolt.persistence.KVStorage +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class DebugSettingsScreenViewModel @Inject constructor( + private val kvStorage: KVStorage, +) : ViewModel() { + fun forgetSidebarSparkShown() { + viewModelScope.launch { + kvStorage.remove("sidebarSpark") + } + } + + fun forgetAllSparks() { + this.forgetSidebarSparkShown() + } +} + +@Composable +fun DebugSettingsScreen( + navController: NavController, + viewModel: DebugSettingsScreenViewModel = hiltViewModel() +) { + Column( + modifier = Modifier + .fillMaxSize() + ) { + PageHeader( + text = "Debug", + showBackButton = true, + onBackButtonClicked = { + navController.popBackStack() + }) + + + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(20.dp) + ) { + Text( + text = "Sparks", + style = MaterialTheme.typography.headlineSmall, + modifier = Modifier.padding(bottom = 10.dp) + ) + Row( + modifier = Modifier.horizontalScroll(rememberScrollState()) + ) { + TextButton(onClick = { viewModel.forgetSidebarSparkShown() }) { + Text("Forget sidebar spark") + } + ElevatedButton(onClick = { viewModel.forgetAllSparks() }) { + Text("Forget all sparks") + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt b/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt index abb16071..441cca7c 100644 --- a/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt +++ b/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Info +import androidx.compose.material.icons.filled.Settings import androidx.compose.material3.Divider import androidx.compose.material3.Icon import androidx.compose.material3.Text @@ -18,6 +19,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.navigation.NavController +import chat.revolt.BuildConfig import chat.revolt.R import chat.revolt.components.generic.PageHeader import chat.revolt.components.generic.SheetClickable @@ -78,6 +80,24 @@ fun SettingsScreen( navController.navigate("about") } + if (BuildConfig.DEBUG) { + SheetClickable( + icon = { modifier -> + Icon( + imageVector = Icons.Default.Settings, + contentDescription = "Debug", + modifier = modifier + ) + }, + label = { textStyle -> + Text(text = "Debug", style = textStyle) + }, + modifier = Modifier.testTag("settings_view_debug") + ) { + navController.navigate("settings/debug") + } + } + Divider() SheetClickable( @@ -109,7 +129,8 @@ fun SettingsScreen( }, modifier = Modifier.testTag("settings_view_logout") ) { - Toast.makeText(navController.context, "Not implemented yet", Toast.LENGTH_SHORT).show() + Toast.makeText(navController.context, "Not implemented yet", Toast.LENGTH_SHORT) + .show() } } } diff --git a/app/src/main/res/raw/open_settings_tutorial.lottie b/app/src/main/res/raw/open_settings_tutorial.lottie new file mode 100644 index 0000000000000000000000000000000000000000..082eb081378cac7d0e1719fb5a12e048a704bce4 GIT binary patch literal 1647 zcmWIWW@Zs#U|`??Vg`math}a^fb?D<<^|&1#JtS3)Z!Aotm6DU)pL$~O$Gw27j~by zC6%>;iM`+{Z%_9jpRHW7#%raVckEuPlm6-7`S}Og>~B7?ba`>kxT1w`gQ4%!sO4qInq``9a++zHu1TUrims)pfr)OKkzqO72WqYqI)9yTIJ(TIVUGf+17pF|2^X=8Q%Mj zo0{Fb%d)|xuK=nXwxmzPOjV`H6Sbr5~xT=ZfxZ4FB88`#0>^U6aTq=iHOZPMqMn z)%cWCJ3hiud`9oq4HDMQ$M#Eb%wXKdcQ(jE!(gGaWTwty`SzeA$_JBT_NFlwx~knw z`)oSXOiZYdi%Ij0xAykxVb^dN~-@7OGgA_r1sp*W5HY-j_N#Q{H>X5)-Yd0d_v@8`PnnBKPiyXi`8JY ze#G`ysjpO}B1gPwVQ5>-1^4+Z;pf@wmpryQDWAUbv*ya>YVOZ0pXJy6D|r2fHL0=1 z^n|>{5$<0ic?KU0swNbx8T%+3*e5bT<9v2c{St68V!oV?>YH4yJ_VCop+?&h+%$~%cF#S# z$+gsL*0wq8PlT*&;ackE=9Tj7-}2XbeLd$z2zHUbW0N zBY-nwwMNkx?+UWmu#=6eH$Wmx0i0YmD`eadGT`Y z4AbjJc1cdoGuig|LhpgL_g|Mi_P=)AYWLI)*Dt@0dvM9Ud#!tZ-G+q6wd~w4w|!2y z*|>Bw)6J4*-8CP2&fWf_xl-BQ!906&rD&V*`3=QU?pBk1+-?P*|JJwnUEy8(Q^(HE zaX-Yr!p5Y7D@6Ois+yP0pI5~>D*3Hf;8Kq^&TA9O{ZWb;c6@^xuY^%gcS@%+=VN>g%UY zvU7Oju9{ZQ62f&T?nSnod(6>_WT$4$PhM|7Y8>}(yHir6ycwAo7;u-~z%mdCpp@n4TG7i+gg#JJKu$>-;LXYgGKC2U=K|?H HtRNl$A1%vA literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 80b06b0c..f0deccbb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -244,6 +244,11 @@ Share video Share image + The settings are in the sidebar + You can open the sidebar by swiping from the left edge of the screen. + Then long tap your profile picture to open the settings. + Got it + Appearance Theme System