commit 14d516975857dae79a784c4662f67d403c57e256
parent 75857946d5b00113a8ca2fc2f4dbcbfb9c7f2aee
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Sun,  1 Oct 2023 15:55:07 +0200

feat(core/config): dynamic change listener
- organize imports

Diffstat:
Mapp/src/main/kotlin/me/rhunk/snapenhance/bridge/BridgeService.kt | 4++++
Mapp/src/main/kotlin/me/rhunk/snapenhance/download/DownloadProcessor.kt | 9++-------
Mapp/src/main/kotlin/me/rhunk/snapenhance/download/FFMpegProcessor.kt | 2+-
Mapp/src/main/kotlin/me/rhunk/snapenhance/messaging/StreaksReminder.kt | 2+-
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/Navigation.kt | 16++--------------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/downloads/DownloadsSection.kt | 31+++----------------------------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/features/FeaturesSection.kt | 50++++----------------------------------------------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/AddFriendDialog.kt | 26+++-----------------------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/ScopeContent.kt | 3+--
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/SocialSection.kt | 31++++---------------------------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/setup/SetupActivity.kt | 8+-------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/setup/screens/impl/MappingsScreen.kt | 7+------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/setup/screens/impl/PermissionsScreen.kt | 16++--------------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/util/AlertDialogs.kt | 15++-------------
Mcore/src/main/aidl/me/rhunk/snapenhance/bridge/BridgeInterface.aidl | 3+++
Acore/src/main/aidl/me/rhunk/snapenhance/bridge/ConfigStateListener.aidl | 8++++++++
Mcore/src/main/kotlin/me/rhunk/snapenhance/SnapEnhance.kt | 50+++++++++++++++++++++++++++++++++++++++++++++++++-
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/bridge/BridgeClient.kt | 3+++
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/config/ConfigObjects.kt | 21+++++++++++++++------
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/config/ModConfig.kt | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/DownloaderConfig.kt | 4++--
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Experimental.kt | 11+++++++----
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Global.kt | 4++--
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/MessagingTweaks.kt | 8++++----
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/RootConfig.kt | 2+-
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Scripting.kt | 4++--
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/UserInterfaceTweaks.kt | 20++++++++++----------
Mcore/src/main/kotlin/me/rhunk/snapenhance/features/impl/tweaks/DisableVideoLengthRestriction.kt | 2+-
Mcore/src/main/kotlin/me/rhunk/snapenhance/features/impl/tweaks/Notifications.kt | 1-
Mcore/src/main/kotlin/me/rhunk/snapenhance/manager/impl/ActionManager.kt | 2+-
30 files changed, 195 insertions(+), 224 deletions(-)

diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/bridge/BridgeService.kt b/app/src/main/kotlin/me/rhunk/snapenhance/bridge/BridgeService.kt @@ -193,5 +193,9 @@ class BridgeService : Service() { remoteSideContext.log.error("Failed to close settings overlay", it) } } + + override fun registerConfigStateListener(listener: ConfigStateListener) { + remoteSideContext.config.configStateListener = listener + } } } diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/download/DownloadProcessor.kt b/app/src/main/kotlin/me/rhunk/snapenhance/download/DownloadProcessor.kt @@ -17,15 +17,10 @@ import me.rhunk.snapenhance.Constants import me.rhunk.snapenhance.RemoteSideContext import me.rhunk.snapenhance.bridge.DownloadCallback import me.rhunk.snapenhance.core.download.DownloadManagerClient -import me.rhunk.snapenhance.data.FileType -import me.rhunk.snapenhance.core.download.data.DownloadMediaType -import me.rhunk.snapenhance.core.download.data.DownloadMetadata -import me.rhunk.snapenhance.core.download.data.DownloadRequest -import me.rhunk.snapenhance.core.download.data.DownloadStage -import me.rhunk.snapenhance.core.download.data.InputMedia -import me.rhunk.snapenhance.core.download.data.SplitMediaAssetType +import me.rhunk.snapenhance.core.download.data.* import me.rhunk.snapenhance.core.util.download.RemoteMediaResolver import me.rhunk.snapenhance.core.util.snap.MediaDownloaderHelper +import me.rhunk.snapenhance.data.FileType import java.io.File import java.io.InputStream import java.net.HttpURLConnection diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/download/FFMpegProcessor.kt b/app/src/main/kotlin/me/rhunk/snapenhance/download/FFMpegProcessor.kt @@ -4,10 +4,10 @@ import com.arthenica.ffmpegkit.FFmpegKit import com.arthenica.ffmpegkit.FFmpegSession import com.arthenica.ffmpegkit.Level import kotlinx.coroutines.suspendCancellableCoroutine -import me.rhunk.snapenhance.core.logger.LogLevel import me.rhunk.snapenhance.LogManager import me.rhunk.snapenhance.core.Logger import me.rhunk.snapenhance.core.config.impl.DownloaderConfig +import me.rhunk.snapenhance.core.logger.LogLevel import java.io.File import java.util.concurrent.Executors diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/messaging/StreaksReminder.kt b/app/src/main/kotlin/me/rhunk/snapenhance/messaging/StreaksReminder.kt @@ -14,8 +14,8 @@ import me.rhunk.snapenhance.R import me.rhunk.snapenhance.RemoteSideContext import me.rhunk.snapenhance.SharedContextHolder import me.rhunk.snapenhance.bridge.ForceStartActivity -import me.rhunk.snapenhance.ui.util.ImageRequestHelper import me.rhunk.snapenhance.core.util.snap.BitmojiSelfie +import me.rhunk.snapenhance.ui.util.ImageRequestHelper class StreaksReminder( private val remoteSideContext: RemoteSideContext? = null diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/Navigation.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/Navigation.kt @@ -4,22 +4,10 @@ import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.NavigationBar -import androidx.compose.material3.NavigationBarItem -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/downloads/DownloadsSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/downloads/DownloadsSection.kt @@ -4,40 +4,15 @@ import android.content.Intent import android.net.Uri import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.FilterList import androidx.compose.material.icons.filled.OpenInNew -import androidx.compose.material3.Card -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.FilledIconButton -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.IconButtonDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Text -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.setValue +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/features/FeaturesSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/features/FeaturesSection.kt @@ -6,21 +6,7 @@ import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.widthIn -import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape @@ -32,30 +18,8 @@ import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.OpenInNew import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.rounded.Save -import androidx.compose.material3.BottomSheetScaffoldState -import androidx.compose.material3.Card -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FilledIconButton -import androidx.compose.material3.FloatingActionButton -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.Switch -import androidx.compose.material3.Text -import androidx.compose.material3.TextField -import androidx.compose.material3.TextFieldDefaults -import androidx.compose.material3.rememberBottomSheetScaffoldState -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.setValue +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester @@ -73,13 +37,7 @@ import androidx.navigation.navigation import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import me.rhunk.snapenhance.core.config.ConfigContainer -import me.rhunk.snapenhance.core.config.ConfigFlag -import me.rhunk.snapenhance.core.config.DataProcessors -import me.rhunk.snapenhance.core.config.FeatureNotice -import me.rhunk.snapenhance.core.config.PropertyKey -import me.rhunk.snapenhance.core.config.PropertyPair -import me.rhunk.snapenhance.core.config.PropertyValue +import me.rhunk.snapenhance.core.config.* import me.rhunk.snapenhance.ui.manager.MainActivity import me.rhunk.snapenhance.ui.manager.Section import me.rhunk.snapenhance.ui.util.* diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/AddFriendDialog.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/AddFriendDialog.kt @@ -1,33 +1,13 @@ package me.rhunk.snapenhance.ui.manager.sections.social import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.Checkbox -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.onGloballyPositioned diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/ScopeContent.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/ScopeContent.kt @@ -12,7 +12,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -25,9 +24,9 @@ import kotlinx.coroutines.launch import me.rhunk.snapenhance.RemoteSideContext import me.rhunk.snapenhance.core.messaging.MessagingRuleType import me.rhunk.snapenhance.core.messaging.SocialScope -import me.rhunk.snapenhance.ui.util.BitmojiImage import me.rhunk.snapenhance.core.util.snap.BitmojiSelfie import me.rhunk.snapenhance.ui.util.AlertDialogs +import me.rhunk.snapenhance.ui.util.BitmojiImage import me.rhunk.snapenhance.ui.util.Dialog import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/SocialSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/SocialSection.kt @@ -2,16 +2,7 @@ package me.rhunk.snapenhance.ui.manager.sections.social import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState @@ -19,22 +10,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Add import androidx.compose.material.icons.rounded.DeleteForever -import androidx.compose.material3.Card -import androidx.compose.material3.FloatingActionButton -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Tab -import androidx.compose.material3.TabRow -import androidx.compose.material3.TabRowDefaults -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector @@ -53,11 +30,11 @@ import me.rhunk.snapenhance.R import me.rhunk.snapenhance.core.messaging.MessagingFriendInfo import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo import me.rhunk.snapenhance.core.messaging.SocialScope +import me.rhunk.snapenhance.core.util.snap.BitmojiSelfie import me.rhunk.snapenhance.ui.manager.Section import me.rhunk.snapenhance.ui.util.AlertDialogs import me.rhunk.snapenhance.ui.util.BitmojiImage import me.rhunk.snapenhance.ui.util.pagerTabIndicatorOffset -import me.rhunk.snapenhance.core.util.snap.BitmojiSelfie class SocialSection : Section() { private lateinit var friendList: List<MessagingFriendInfo> diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/setup/SetupActivity.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/setup/SetupActivity.kt @@ -7,13 +7,7 @@ import androidx.activity.compose.BackHandler import androidx.activity.compose.setContent import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowForwardIos import androidx.compose.material.icons.filled.Check diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/setup/screens/impl/MappingsScreen.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/setup/screens/impl/MappingsScreen.kt @@ -6,12 +6,7 @@ import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/setup/screens/impl/PermissionsScreen.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/setup/screens/impl/PermissionsScreen.kt @@ -10,27 +10,15 @@ import android.os.Build import android.os.PowerManager import android.provider.Settings import androidx.activity.ComponentActivity -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material3.Button import androidx.compose.material3.Icon import androidx.compose.material3.OutlinedCard import androidx.compose.material3.Text -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.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch import me.rhunk.snapenhance.ui.setup.screens.SetupScreen diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/util/AlertDialogs.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/util/AlertDialogs.kt @@ -2,21 +2,10 @@ package me.rhunk.snapenhance.ui.util import androidx.compose.foundation.ScrollState import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Button -import androidx.compose.material3.Card -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Switch -import androidx.compose.material3.Text -import androidx.compose.material3.TextField +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf diff --git a/core/src/main/aidl/me/rhunk/snapenhance/bridge/BridgeInterface.aidl b/core/src/main/aidl/me/rhunk/snapenhance/bridge/BridgeInterface.aidl @@ -6,6 +6,7 @@ import me.rhunk.snapenhance.bridge.SyncCallback; import me.rhunk.snapenhance.bridge.scripting.IScripting; import me.rhunk.snapenhance.bridge.e2ee.E2eeInterface; import me.rhunk.snapenhance.bridge.MessageLoggerInterface; +import me.rhunk.snapenhance.bridge.ConfigStateListener; interface BridgeInterface { /** @@ -82,4 +83,6 @@ interface BridgeInterface { void openSettingsOverlay(); void closeSettingsOverlay(); + + void registerConfigStateListener(in ConfigStateListener listener); } \ No newline at end of file diff --git a/core/src/main/aidl/me/rhunk/snapenhance/bridge/ConfigStateListener.aidl b/core/src/main/aidl/me/rhunk/snapenhance/bridge/ConfigStateListener.aidl @@ -0,0 +1,7 @@ +package me.rhunk.snapenhance.bridge; + +oneway interface ConfigStateListener { + void onConfigChanged(); + void onRestartRequired(); + void onCleanCacheRequired(); +}+ \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/SnapEnhance.kt b/core/src/main/kotlin/me/rhunk/snapenhance/SnapEnhance.kt @@ -7,6 +7,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import me.rhunk.snapenhance.action.EnumAction +import me.rhunk.snapenhance.bridge.ConfigStateListener import me.rhunk.snapenhance.bridge.SyncCallback import me.rhunk.snapenhance.core.Logger import me.rhunk.snapenhance.core.bridge.BridgeClient @@ -30,6 +32,7 @@ class SnapEnhance { } private val appContext = ModContext() private var isBridgeInitialized = false + private var isActivityPaused = false private fun hookMainActivity(methodName: String, stage: HookStage = HookStage.AFTER, block: Activity.() -> Unit) { Activity::class.java.hook(methodName, stage, { isBridgeInitialized }) { param -> @@ -84,12 +87,14 @@ class SnapEnhance { hookMainActivity("onPause") { appContext.bridgeClient.closeSettingsOverlay() + isActivityPaused = true } var activityWasResumed = false //we need to reload the config when the app is resumed //FIXME: called twice at first launch hookMainActivity("onResume") { + isActivityPaused = false if (!activityWasResumed) { activityWasResumed = true return@hookMainActivity @@ -104,6 +109,8 @@ class SnapEnhance { private fun init(scope: CoroutineScope) { with(appContext) { reloadConfig() + actionManager.init() + initConfigListener() scope.launch(Dispatchers.IO) { initNative() translation.userLocale = getConfigLocale() @@ -125,7 +132,6 @@ class SnapEnhance { measureTimeMillis { with(appContext) { features.onActivityCreate() - actionManager.init() scriptRuntime.eachModule { callFunction("module.onSnapActivity", mainActivity!!) } } }.also { time -> @@ -148,6 +154,48 @@ class SnapEnhance { } } + private fun initConfigListener() { + val tasks = linkedSetOf<() -> Unit>() + hookMainActivity("onResume") { + tasks.forEach { it() } + } + + fun runLater(task: () -> Unit) { + if (isActivityPaused) { + tasks.add(task) + } else { + task() + } + } + + appContext.apply { + bridgeClient.registerConfigStateListener(object: ConfigStateListener.Stub() { + override fun onConfigChanged() { + log.verbose("onConfigChanged") + reloadConfig() + } + + override fun onRestartRequired() { + log.verbose("onRestartRequired") + runLater { + log.verbose("softRestart") + softRestartApp(saveSettings = false) + } + } + + override fun onCleanCacheRequired() { + log.verbose("onCleanCacheRequired") + tasks.clear() + runLater { + log.verbose("cleanCache") + actionManager.execute(EnumAction.CLEAN_CACHE) + } + } + }) + } + + } + private fun syncRemote() { appContext.executeAsync { bridgeClient.sync(object : SyncCallback.Stub() { diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/bridge/BridgeClient.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/bridge/BridgeClient.kt @@ -12,6 +12,7 @@ import android.os.IBinder import de.robv.android.xposed.XposedHelpers import me.rhunk.snapenhance.ModContext import me.rhunk.snapenhance.bridge.BridgeInterface +import me.rhunk.snapenhance.bridge.ConfigStateListener import me.rhunk.snapenhance.bridge.DownloadCallback import me.rhunk.snapenhance.bridge.SyncCallback import me.rhunk.snapenhance.bridge.e2ee.E2eeInterface @@ -144,4 +145,6 @@ class BridgeClient( fun openSettingsOverlay() = service.openSettingsOverlay() fun closeSettingsOverlay() = service.closeSettingsOverlay() + + fun registerConfigStateListener(listener: ConfigStateListener) = service.registerConfigStateListener(listener) } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/ConfigObjects.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/ConfigObjects.kt @@ -22,10 +22,12 @@ enum class FeatureNotice( enum class ConfigFlag( val id: Int ) { - NO_TRANSLATE(0b0001), - HIDDEN(0b0010), - FOLDER(0b0100), - NO_DISABLE_KEY(0b1000) + NO_TRANSLATE(0b000001), + HIDDEN(0b000010), + FOLDER(0b000100), + NO_DISABLE_KEY(0b001000), + REQUIRE_RESTART(0b010000), + REQUIRE_CLEAN_CACHE(0b100000) } class ConfigParams( @@ -47,6 +49,13 @@ class ConfigParams( fun addFlags(vararg values: ConfigFlag) { this._flags = (this._flags ?: 0) or values.fold(0) { acc, flag -> acc or flag.id } } + + fun requireRestart() { + addFlags(ConfigFlag.REQUIRE_RESTART) + } + fun requireCleanCache() { + addFlags(ConfigFlag.REQUIRE_CLEAN_CACHE) + } } class PropertyValue<T>( @@ -65,7 +74,7 @@ class PropertyValue<T>( fun getNullable() = value?.takeIf { it != "null" } fun isEmpty() = value == null || value == "null" || value.toString().isEmpty() fun get() = getNullable() ?: throw IllegalStateException("Property is not set") - fun set(value: T?) { this.value = value } + fun set(value: T?) { setAny(value) } @Suppress("UNCHECKED_CAST") fun setAny(value: Any?) { this.value = value as T? } @@ -79,7 +88,7 @@ data class PropertyKey<T>( val dataType: DataProcessors.PropertyDataProcessor<T>, val params: ConfigParams = ConfigParams(), ) { - val parentKey by lazy { _parent() } + private val parentKey by lazy { _parent() } fun propertyOption(translation: LocaleWrapper, key: String): String { if (key == "null") { diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/ModConfig.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/ModConfig.kt @@ -4,6 +4,8 @@ import android.content.Context import com.google.gson.Gson import com.google.gson.GsonBuilder import com.google.gson.JsonObject +import me.rhunk.snapenhance.bridge.ConfigStateListener +import me.rhunk.snapenhance.core.Logger import me.rhunk.snapenhance.core.bridge.BridgeClient import me.rhunk.snapenhance.core.bridge.FileLoaderWrapper import me.rhunk.snapenhance.core.bridge.types.BridgeFileType @@ -18,7 +20,10 @@ class ModConfig { private val file = FileLoaderWrapper(BridgeFileType.CONFIG, "{}".toByteArray(Charsets.UTF_8)) var wasPresent by Delegates.notNull<Boolean>() + /* Used to notify the bridge client about config changes */ + var configStateListener: ConfigStateListener? = null lateinit var root: RootConfig + private set private fun load() { root = RootConfig() @@ -54,6 +59,57 @@ class ModConfig { } fun writeConfig() { + var shouldRestart = false + var shouldCleanCache = false + var configChanged = false + + fun compareDiff(originalContainer: ConfigContainer, modifiedContainer: ConfigContainer) { + val parentContainerFlags = modifiedContainer.parentContainerKey?.params?.flags ?: emptySet() + + parentContainerFlags.takeIf { originalContainer.hasGlobalState }?.apply { + if (modifiedContainer.globalState != originalContainer.globalState) { + configChanged = true + if (contains(ConfigFlag.REQUIRE_RESTART)) shouldRestart = true + if (contains(ConfigFlag.REQUIRE_CLEAN_CACHE)) shouldCleanCache = true + } + } + + for (property in modifiedContainer.properties) { + val modifiedValue = property.value.getNullable() + val originalValue = originalContainer.properties.entries.firstOrNull { + it.key.name == property.key.name + }?.value?.getNullable() + + if (originalValue is ConfigContainer && modifiedValue is ConfigContainer) { + compareDiff(originalValue, modifiedValue) + continue + } + + if (modifiedValue != originalValue) { + val flags = property.key.params.flags + parentContainerFlags + configChanged = true + if (flags.contains(ConfigFlag.REQUIRE_RESTART)) shouldRestart = true + if (flags.contains(ConfigFlag.REQUIRE_CLEAN_CACHE)) shouldCleanCache = true + } + } + } + + configStateListener?.also { + runCatching { + compareDiff(RootConfig().apply { + fromJson(gson.fromJson(file.read().toString(Charsets.UTF_8), JsonObject::class.java)) + }, root) + + if (configChanged) { + it.onConfigChanged() + if (shouldCleanCache) it.onCleanCacheRequired() + else if (shouldRestart) it.onRestartRequired() + } + }.onFailure { + Logger.directError("Error while calling config state listener", it, "ConfigStateListener") + } + } + file.write(exportToString().toByteArray(Charsets.UTF_8)) } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/DownloaderConfig.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/DownloaderConfig.kt @@ -17,7 +17,7 @@ class DownloaderConfig : ConfigContainer() { val customAudioCodec = string("custom_audio_codec") { addFlags(ConfigFlag.NO_TRANSLATE) } } - val saveFolder = string("save_folder") { addFlags(ConfigFlag.FOLDER) } + val saveFolder = string("save_folder") { addFlags(ConfigFlag.FOLDER); requireRestart() } val autoDownloadSources = multiple("auto_download_sources", "friend_snaps", "friend_stories", @@ -41,7 +41,7 @@ class DownloaderConfig : ConfigContainer() { val forceVoiceNoteFormat = unique("force_voice_note_format", "aac", "mp3", "opus") { addFlags(ConfigFlag.NO_TRANSLATE) } - val downloadProfilePictures = boolean("download_profile_pictures") + val downloadProfilePictures = boolean("download_profile_pictures") { requireRestart() } val chatDownloadContextMenu = boolean("chat_download_context_menu") val ffmpegOptions = container("ffmpeg_options", FFMpegOptions()) { addNotices(FeatureNotice.UNSTABLE) } val logging = multiple("logging", "started", "success", "progress", "failure").apply { diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Experimental.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Experimental.kt @@ -4,16 +4,19 @@ import me.rhunk.snapenhance.core.config.ConfigContainer import me.rhunk.snapenhance.core.config.FeatureNotice class Experimental : ConfigContainer() { - val nativeHooks = container("native_hooks", NativeHooks()) { icon = "Memory" } + val nativeHooks = container("native_hooks", NativeHooks()) { icon = "Memory"; requireRestart() } val spoof = container("spoof", Spoof()) { icon = "Fingerprint" } val appPasscode = string("app_passcode") val appLockOnResume = boolean("app_lock_on_resume") val infiniteStoryBoost = boolean("infinite_story_boost") val meoPasscodeBypass = boolean("meo_passcode_bypass") val unlimitedMultiSnap = boolean("unlimited_multi_snap") { addNotices(FeatureNotice.BAN_RISK)} - val noFriendScoreDelay = boolean("no_friend_score_delay") - val e2eEncryption = container("e2ee", E2EEConfig()) - val hiddenSnapchatPlusFeatures = boolean("hidden_snapchat_plus_features") { addNotices(FeatureNotice.BAN_RISK, FeatureNotice.UNSTABLE) } + val noFriendScoreDelay = boolean("no_friend_score_delay") { requireRestart()} + val e2eEncryption = container("e2ee", E2EEConfig()) { requireRestart()} + val hiddenSnapchatPlusFeatures = boolean("hidden_snapchat_plus_features") { + addNotices(FeatureNotice.BAN_RISK, FeatureNotice.UNSTABLE) + requireRestart() + } val addFriendSourceSpoof = unique("add_friend_source_spoof", "added_by_username", "added_by_mention", diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Global.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Global.kt @@ -4,11 +4,11 @@ import me.rhunk.snapenhance.core.config.ConfigContainer import me.rhunk.snapenhance.core.config.FeatureNotice class Global : ConfigContainer() { - val snapchatPlus = boolean("snapchat_plus") { addNotices(FeatureNotice.BAN_RISK) } + val snapchatPlus = boolean("snapchat_plus") { addNotices(FeatureNotice.BAN_RISK); requireRestart() } val disableMetrics = boolean("disable_metrics") val blockAds = boolean("block_ads") val disableVideoLengthRestrictions = boolean("disable_video_length_restrictions") { addNotices(FeatureNotice.BAN_RISK) } - val disableGooglePlayDialogs = boolean("disable_google_play_dialogs") + val disableGooglePlayDialogs = boolean("disable_google_play_dialogs") { requireRestart() } val forceMediaSourceQuality = boolean("force_media_source_quality") val disableSnapSplitting = boolean("disable_snap_splitting") { addNotices(FeatureNotice.INTERNAL_BEHAVIOR) } } \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/MessagingTweaks.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/MessagingTweaks.kt @@ -16,16 +16,16 @@ class MessagingTweaks : ConfigContainer() { "NOTE", "EXTERNAL_MEDIA", "STICKER" - ) - val snapToChatMedia = boolean("snap_to_chat_media") + ) { requireRestart() } + val snapToChatMedia = boolean("snap_to_chat_media") { requireRestart() } val preventMessageSending = multiple("prevent_message_sending", *NotificationType.getOutgoingValues().map { it.key }.toTypedArray()) { customOptionTranslationPath = "features.options.notifications" } - val betterNotifications = multiple("better_notifications", "snap", "chat", "reply_button", "download_button", "group") + val betterNotifications = multiple("better_notifications", "snap", "chat", "reply_button", "download_button", "group") { requireRestart() } val notificationBlacklist = multiple("notification_blacklist", *NotificationType.getIncomingValues().map { it.key }.toTypedArray()) { customOptionTranslationPath = "features.options.notifications" } - val messageLogger = boolean("message_logger") { addNotices(FeatureNotice.UNSTABLE) } + val messageLogger = boolean("message_logger") { addNotices(FeatureNotice.UNSTABLE); requireRestart() } val galleryMediaSendOverride = boolean("gallery_media_send_override") val messagePreviewLength = integer("message_preview_length", defaultValue = 20) } \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/RootConfig.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/RootConfig.kt @@ -9,7 +9,7 @@ class RootConfig : ConfigContainer() { val messaging = container("messaging", MessagingTweaks()) { icon = "Send" } val global = container("global", Global()) { icon = "MiscellaneousServices" } val rules = container("rules", Rules()) { icon = "Rule" } - val camera = container("camera", Camera()) { icon = "Camera"} + val camera = container("camera", Camera()) { icon = "Camera"; requireRestart() } val streaksReminder = container("streaks_reminder", StreaksReminderConfig()) { icon = "Alarm" } val experimental = container("experimental", Experimental()) { icon = "Science"; addNotices(FeatureNotice.UNSTABLE) diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Scripting.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/Scripting.kt @@ -4,7 +4,7 @@ import me.rhunk.snapenhance.core.config.ConfigContainer import me.rhunk.snapenhance.core.config.ConfigFlag class Scripting : ConfigContainer() { - val developerMode = boolean("developer_mode", false) - val moduleFolder = string("module_folder", "modules") { addFlags(ConfigFlag.FOLDER) } + val developerMode = boolean("developer_mode", false) { requireRestart() } + val moduleFolder = string("module_folder", "modules") { addFlags(ConfigFlag.FOLDER); requireRestart() } val hotReload = boolean("hot_reload", false) } \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/UserInterfaceTweaks.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/UserInterfaceTweaks.kt @@ -8,7 +8,7 @@ import me.rhunk.snapenhance.features.impl.ui.ClientBootstrapOverride class UserInterfaceTweaks : ConfigContainer() { inner class BootstrapOverride : ConfigContainer() { val appAppearance = unique("app_appearance", "always_light", "always_dark") - val homeTab = unique("home_tab", *ClientBootstrapOverride.tabs) { addNotices(FeatureNotice.UNSTABLE) } + val homeTab = unique("home_tab", *ClientBootstrapOverride.tabs) { addNotices(FeatureNotice.UNSTABLE) } } val friendFeedMenuButtons = multiple( @@ -17,20 +17,20 @@ class UserInterfaceTweaks : ConfigContainer() { set(mutableListOf("conversation_info", MessagingRuleType.STEALTH.key)) } val friendFeedMenuPosition = integer("friend_feed_menu_position", defaultValue = 1) - val amoledDarkMode = boolean("amoled_dark_mode") { addNotices(FeatureNotice.UNSTABLE) } - val bootstrapOverride = container("bootstrap_override", BootstrapOverride()) - val mapFriendNameTags = boolean("map_friend_nametags") - val streakExpirationInfo = boolean("streak_expiration_info") + val amoledDarkMode = boolean("amoled_dark_mode") { addNotices(FeatureNotice.UNSTABLE); requireRestart() } + val bootstrapOverride = container("bootstrap_override", BootstrapOverride()) { requireRestart() } + val mapFriendNameTags = boolean("map_friend_nametags") { requireRestart() } + val streakExpirationInfo = boolean("streak_expiration_info") { requireRestart() } val hideStorySections = multiple("hide_story_sections", - "hide_friend_suggestions", "hide_friends", "hide_suggested", "hide_for_you") + "hide_friend_suggestions", "hide_friends", "hide_suggested", "hide_for_you") { requireRestart() } val hideUiComponents = multiple("hide_ui_components", "hide_voice_record_button", "hide_stickers_button", "hide_live_location_share_button", "hide_chat_call_buttons", "hide_profile_call_buttons" - ) - val ddBitmojiSelfie = boolean("2d_bitmoji_selfie") - val disableSpotlight = boolean("disable_spotlight") - val storyViewerOverride = unique("story_viewer_override", "DISCOVER_PLAYBACK_SEEKBAR", "VERTICAL_STORY_VIEWER") + ) { requireRestart() } + val ddBitmojiSelfie = boolean("2d_bitmoji_selfie") { requireCleanCache() } + val disableSpotlight = boolean("disable_spotlight") { requireRestart() } + val storyViewerOverride = unique("story_viewer_override", "DISCOVER_PLAYBACK_SEEKBAR", "VERTICAL_STORY_VIEWER") { requireRestart() } } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/tweaks/DisableVideoLengthRestriction.kt b/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/tweaks/DisableVideoLengthRestriction.kt @@ -18,7 +18,7 @@ class DisableVideoLengthRestriction : Feature("DisableVideoLengthRestriction", l val isState by context.config.global.disableVideoLengthRestrictions //fix black videos when story is posted - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + if (isState && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val postedStorySnapFolder = File(context.androidContext.filesDir, "file_manager/posted_story_snap") fileObserver = (object : FileObserver(postedStorySnapFolder, MOVED_TO) { diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/tweaks/Notifications.kt b/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/tweaks/Notifications.kt @@ -185,7 +185,6 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN } } - @OptIn(ExperimentalEncodingApi::class) private fun fetchMessagesResult(conversationId: String, messages: List<Message>) { val sendNotificationData = { notificationData: NotificationData, forceCreate: Boolean -> val notificationId = if (forceCreate) System.nanoTime().toInt() else notificationData.id diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/manager/impl/ActionManager.kt b/core/src/main/kotlin/me/rhunk/snapenhance/manager/impl/ActionManager.kt @@ -28,7 +28,7 @@ class ActionManager( intent.removeExtra(ACTION_PARAMETER) } - private fun execute(action: EnumAction) { + fun execute(action: EnumAction) { actions[action.key]?.run() if (action.exitOnFinish) { modContext.forceCloseApp()