From 1ae48fdfc11188e7ee50f441fd6b948e8553d441 Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 10 Feb 2026 14:24:02 +0100 Subject: [PATCH] Use new UI from library --- app/src/main/AndroidManifest.xml | 7 + .../distributor/sunup/Distributor.kt | 3 +- .../distributor/sunup/SunupAppConfig.kt | 34 +++ .../distributor/sunup/activities/AppAction.kt | 97 -------- .../sunup/activities/ApplicationRowState.kt | 25 -- .../activities/DistribMigrationViewModel.kt | 73 ------ .../sunup/activities/MainActivity.kt | 46 ++-- .../sunup/activities/MainViewModel.kt | 89 ------- .../activities/RegistrationsViewModel.kt | 20 -- .../sunup/activities/SettingsViewModel.kt | 74 ------ .../sunup/activities/ThemeViewModel.kt | 25 -- .../distributor/sunup/activities/UiAction.kt | 25 -- .../sunup/activities/ViewModelFactory.kt | 50 ---- .../distributor/sunup/activities/ui/AppUi.kt | 159 ------------ .../sunup/activities/ui/ChangeServerUi.kt | 75 ------ .../sunup/activities/ui/MainScreen.kt | 230 ------------------ .../sunup/activities/ui/MainUiState.kt | 3 - .../activities/ui/PrivacyPolicyDialogUi.kt | 56 ----- .../sunup/activities/ui/SettingsScreen.kt | 121 --------- .../sunup/activities/ui/SettingsState.kt | 21 -- .../distributor/sunup/api/ServerConnection.kt | 5 +- .../sunup/services/InternalServiceImpl.kt | 80 ++++++ .../sunup/services/MainRegistrationCounter.kt | 4 +- ...tionManager.kt => MigrationManagerImpl.kt} | 4 +- .../sunup/services/SourceManager.kt | 2 +- .../sunup/utils/DebugInformation.kt | 15 -- .../distributor/sunup/utils/Notifications.kt | 4 +- 27 files changed, 154 insertions(+), 1193 deletions(-) create mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/SunupAppConfig.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/AppAction.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/ApplicationRowState.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/DistribMigrationViewModel.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/MainViewModel.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/RegistrationsViewModel.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/SettingsViewModel.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/ThemeViewModel.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/UiAction.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/ViewModelFactory.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/AppUi.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/ChangeServerUi.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/MainScreen.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/MainUiState.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/PrivacyPolicyDialogUi.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/SettingsScreen.kt delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/SettingsState.kt create mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/services/InternalServiceImpl.kt rename app/src/main/java/org/unifiedpush/distributor/sunup/services/{MigrationManager.kt => MigrationManagerImpl.kt} (75%) delete mode 100644 app/src/main/java/org/unifiedpush/distributor/sunup/utils/DebugInformation.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 334d822..01deaa6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,6 +21,7 @@ @@ -34,6 +35,12 @@ + + + + + ) : Action() - data object FallbackIntroShown : Action() - class FallbackDistribSelected(val distributor: String?) : Action() - class MigrateToDistrib(val distributor: String) : Action() - data object ReactivateUnifiedPush : Action() - } - - fun handle(context: Context) { - when (action) { - is Action.RestartService -> restartService(context) - is Action.NewPushServer -> newPushServer(context, action) - is Action.ShowToasts -> showToasts(context, action) - is Action.DeleteRegistration -> deleteRegistration(context, action) - is Action.FallbackIntroShown -> fallbackIntroShown(context) - is Action.FallbackDistribSelected -> fallbackDistribSelected(context, action) - is Action.MigrateToDistrib -> migrateToDistrib(context, action) - is Action.ReactivateUnifiedPush -> reactivateUnifiedPush(context) - } - } - - private fun restartService(context: Context) { - Log.d(TAG, "Restarting the Listener") - SourceManager.clearFails() - FgService.stopService { - RestartWorker.run(context, delay = 0) - } - } - - private fun newPushServer(context: Context, action: Action.NewPushServer) { - ApiUrlCandidate.test(context, action.url) - } - - private fun showToasts(context: Context, action: Action.ShowToasts) { - AppStore(context).showToasts = action.enable - } - - private fun deleteRegistration(context: Context, action: Action.DeleteRegistration) { - action.registrations.forEach { - Distributor.deleteApp(context, it) - } - } - - private fun fallbackIntroShown(context: Context) { - MigrationManager().setFallbackIntroShown(context) - } - - /** - * Save fallback service - * - * If fallback is disabled and we have already send TEMP_UNAVAILABLE: - * we send the endpoint again - */ - private fun fallbackDistribSelected(context: Context, action: Action.FallbackDistribSelected) { - MigrationManager() - .selectFallbackService( - context, - action.distributor, - SourceManager.shouldSendFallback - ) - } - - private fun migrateToDistrib(context: Context, action: Action.MigrateToDistrib) { - MigrationManager().migrate(context, action.distributor) - } - - private fun reactivateUnifiedPush(context: Context) { - MigrationManager().reactivate(context) - } -} - -fun ViewModel.publishAction(action: AppAction) { - viewModelScope.launch { - EventBus.publish(action) - } -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ApplicationRowState.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ApplicationRowState.kt deleted file mode 100644 index 4d4fb8f..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ApplicationRowState.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities - -import android.content.Context -import org.unifiedpush.android.distributor.ui.compose.state.ApplicationRowState -import org.unifiedpush.distributor.utils.appInfoForMetadata -import org.unifiedpush.distributor.utils.getApplicationIcon -import org.unifiedpush.distributor.utils.getApplicationName - -fun Context.applicationRowState(packageName: String, description: String? = null): ApplicationRowState { - val ai = appInfoForMetadata(packageName) - val title = ai?.let { getApplicationName(it) } ?: packageName - val icon = getApplicationIcon(packageName) - val description = if (title == packageName) { - description ?: "" - } else { - description?.let { "$it — $packageName" } - ?: packageName - } - return ApplicationRowState( - icon = icon, - title = title, - packageName = packageName, - description = description - ) -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/DistribMigrationViewModel.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/DistribMigrationViewModel.kt deleted file mode 100644 index 1ce6ffb..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/DistribMigrationViewModel.kt +++ /dev/null @@ -1,73 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities - -import android.app.Application -import android.content.Context -import org.unifiedpush.android.distributor.ui.compose.DistribMigrationViewModel as UPDistribMigrationViewModel -import org.unifiedpush.android.distributor.ui.compose.state.DistribMigrationState -import org.unifiedpush.distributor.sunup.AppStore -import org.unifiedpush.distributor.sunup.BuildConfig -import org.unifiedpush.distributor.utils.listOtherDistributors - -class DistribMigrationViewModel(state: DistribMigrationState, val application: Application? = null) : UPDistribMigrationViewModel(state) { - constructor(application: Application) : this( - stateFrom(application), - application - ) - - override fun onFallbackDistribSelected(distributor: String?) { - publishAction( - AppAction(AppAction.Action.FallbackDistribSelected(distributor)) - ) - } - - override fun onMigrationDistributorSelected(distributor: String) { - publishAction( - AppAction(AppAction.Action.MigrateToDistrib(distributor)) - ) - } - - override fun onFallbackIntroShown() { - publishAction( - AppAction(AppAction.Action.FallbackIntroShown) - ) - } - - override fun onServiceReactivated() { - publishAction( - AppAction(AppAction.Action.ReactivateUnifiedPush) - ) - } - - override fun refreshDistributors() { - application?.let { context -> - refreshDistributors { - val store = AppStore(context) - val fallbackDistrib = store.fallbackService - return@refreshDistributors context.listOtherDistributors() - .map { packageName -> - context.applicationRowState(packageName).copy( - selected = fallbackDistrib == packageName - ) - }.toSet() - } - } - } - - companion object { - fun stateFrom(context: Context): DistribMigrationState { - val store = AppStore(context) - val fallbackDistrib = store.fallbackService - val distributors = context.listOtherDistributors().map { packageName -> - context.applicationRowState(packageName).copy( - selected = fallbackDistrib == packageName - ) - }.toSet() - return DistribMigrationState( - distributors, - store.fallbackIntroShown, - migrated = store.migrated, - featureEnabled = BuildConfig.SUPPORT_MIGRATIONS - ) - } - } -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/MainActivity.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/MainActivity.kt index 6f8e267..c7eb1e0 100644 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/MainActivity.kt +++ b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/MainActivity.kt @@ -6,53 +6,51 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.lifecycle.viewmodel.compose.viewModel -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch -import org.unifiedpush.distributor.sunup.EventBus +import kotlin.system.exitProcess +import org.unifiedpush.android.distributor.ui.screen.App +import org.unifiedpush.android.distributor.ui.vm.ThemeViewModel +import org.unifiedpush.android.distributor.ui.vm.ViewModelFactory +import org.unifiedpush.distributor.ipc.InternalMessenger +import org.unifiedpush.distributor.ipc.subscribeUiActions import org.unifiedpush.distributor.sunup.Migrations -import org.unifiedpush.distributor.sunup.activities.ThemeViewModel -import org.unifiedpush.distributor.sunup.activities.ui.App +import org.unifiedpush.distributor.sunup.SunupAppConfig import org.unifiedpush.distributor.sunup.activities.ui.theme.AppTheme -import org.unifiedpush.distributor.sunup.services.RestartWorker import org.unifiedpush.distributor.sunup.utils.TAG class MainActivity : ComponentActivity() { - private var jobs: MutableList = emptyList().toMutableList() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - RestartWorker.startPeriodic(this) Migrations(this).run() + val messenger = InternalMessenger(this) + val uiFlow = subscribeUiActions(this) + val appConfig = SunupAppConfig() enableEdgeToEdge() setContent { - val factory = ViewModelFactory(this.application) + val factory = ViewModelFactory( + context = this, + appConfig = appConfig, + messenger = messenger + ) val themeViewModel = viewModel(factory = factory) AppTheme( dynamicColor = themeViewModel.dynamicColors ) { - App(factory, themeViewModel) + App( + appConfig = appConfig, + factory = factory, + themeViewModel = themeViewModel, + uiFlow = uiFlow + ) } - subscribeActions() - } - } - - private fun subscribeActions() { - Log.d(TAG, "Subscribing to actions") - jobs += CoroutineScope(Dispatchers.IO).launch { - EventBus.subscribe { it.handle(this@MainActivity) } } } override fun onDestroy() { Log.d(TAG, "Destroy") - jobs.removeAll { - it.cancel() - true - } super.onDestroy() + exitProcess(0) } } diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/MainViewModel.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/MainViewModel.kt deleted file mode 100644 index a74229a..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/MainViewModel.kt +++ /dev/null @@ -1,89 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities - -import android.app.Application -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableLongStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import org.unifiedpush.android.distributor.ui.compose.BatteryOptimisationViewModel -import org.unifiedpush.android.distributor.ui.compose.RegistrationsViewModel -import org.unifiedpush.android.distributor.ui.compose.state.RegistrationListState -import org.unifiedpush.distributor.sunup.activities.ui.MainUiState - -class MainViewModel( - mainUiState: MainUiState, - val batteryOptimisationViewModel: BatteryOptimisationViewModel, - val registrationsViewModel: RegistrationsViewModel, - val application: Application? = null -) : ViewModel() { - constructor(application: Application) : this( - mainUiState = MainUiState(), - batteryOptimisationViewModel = BatteryOptimisationViewModel(application), - registrationsViewModel = RegistrationsViewModel( - getRegistrationListState(application) - ), - application - ) - - var mainUiState by mutableStateOf(mainUiState) - private set - - private var lastDebugClickTime by mutableLongStateOf(0L) - - private var debugClickCount by mutableIntStateOf(0) - - fun closePermissionDialog() { - viewModelScope.launch { - mainUiState = mainUiState.copy(showPermissionDialog = false) - } - } - - fun refreshRegistrations() { - viewModelScope.launch { - application?.let { - registrationsViewModel.state = getRegistrationListState(it) - } - } - } - - fun deleteSelection() { - viewModelScope.launch { - val state = registrationsViewModel.state - val tokenList = state.list.filter { it.selected }.map { it.token } - publishAction( - AppAction(AppAction.Action.DeleteRegistration(tokenList)) - ) - registrationsViewModel.state = RegistrationListState( - list = state.list.filter { - !it.selected - }, - selectionCount = 0 - ) - } - } - - fun addDebugClick() { - val currentTime = System.currentTimeMillis() - if (currentTime - lastDebugClickTime < 500) { - debugClickCount++ - if (debugClickCount == 5) { - mainUiState = mainUiState.copy(showDebugInfo = true) - } - } else { - debugClickCount = 1 - } - lastDebugClickTime = currentTime - } - - fun dismissDebugInfo() { - mainUiState = mainUiState.copy(showDebugInfo = false) - } - - fun restartService() { - publishAction(AppAction(AppAction.Action.RestartService)) - } -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/RegistrationsViewModel.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/RegistrationsViewModel.kt deleted file mode 100644 index d351892..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/RegistrationsViewModel.kt +++ /dev/null @@ -1,20 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities - -import android.content.Context -import org.unifiedpush.android.distributor.ui.compose.state.RegistrationListState -import org.unifiedpush.android.distributor.ui.compose.state.RegistrationState -import org.unifiedpush.distributor.Database -import org.unifiedpush.distributor.sunup.DatabaseFactory - -fun getRegistrationListState(context: Context): RegistrationListState = RegistrationListState( - list = DatabaseFactory.getDb(context).listApps().map { app -> - getRegistrationState(context, app) - } -) - -fun getRegistrationState(context: Context, app: Database.App): RegistrationState = RegistrationState( - app = context.applicationRowState(app.packageName, app.description), - msgCount = app.msgCount, - token = app.connectorToken, - copyable = false -) diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/SettingsViewModel.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/SettingsViewModel.kt deleted file mode 100644 index baf65fa..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/SettingsViewModel.kt +++ /dev/null @@ -1,74 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities - -import android.app.Application -import android.util.Log -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import java.net.URL -import kotlinx.coroutines.launch -import org.unifiedpush.distributor.sunup.AppStore -import org.unifiedpush.distributor.sunup.BuildConfig -import org.unifiedpush.distributor.sunup.activities.ui.SettingsState -import org.unifiedpush.distributor.sunup.utils.TAG - -class SettingsViewModel(state: SettingsState, val application: Application? = null) : ViewModel() { - constructor(application: Application) : this( - SettingsState.from(application), - application - ) - - var state by mutableStateOf(state) - private set - - fun toggleChangeServer() { - viewModelScope.launch { - state = state.copy(showChangeServerDialog = !state.showChangeServerDialog) - } - } - - fun togglePrivacyPolicy() { - viewModelScope.launch { - state = state.copy(showPrivacyPolicy = !state.showPrivacyPolicy) - } - } - - fun newPushServer(url: String) { - var url = url - viewModelScope.launch { - try { - if (url.isBlank()) { - url = BuildConfig.DEFAULT_API_URL - } - if (url.slice(0..4) !in arrayOf("http:", "https", "ws://", "wss:/")) { - url = "https://$url" - } - URL(url) - state = state.copy( - currentApiUrl = url, - showChangeServerDialog = false - ) - publishAction(AppAction(AppAction.Action.NewPushServer(url))) - } catch (e: Exception) { - Log.d(TAG, "Ignoring url: $url : $e:w") - } - } - } - - fun refreshApiUrl() { - viewModelScope.launch { - application?.let { - state = state.copy(currentApiUrl = AppStore(it).apiUrl) - } - } - } - - fun toggleShowToasts() { - viewModelScope.launch { - state = state.copy(showToasts = !state.showToasts) - publishAction(AppAction(AppAction.Action.ShowToasts(state.showToasts))) - } - } -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ThemeViewModel.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ThemeViewModel.kt deleted file mode 100644 index ad4263d..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ThemeViewModel.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities - -import android.app.Application -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import org.unifiedpush.distributor.sunup.AppStore - -class ThemeViewModel(val application: Application? = null) : ViewModel() { - var dynamicColors by mutableStateOf( - application?.let { AppStore(it).dynamicColors } ?: false - ) - - fun toggleDynamicColors() { - viewModelScope.launch { - dynamicColors = !dynamicColors - application?.run { - AppStore(this).dynamicColors = dynamicColors - } - } - } -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/UiAction.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/UiAction.kt deleted file mode 100644 index fd61914..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/UiAction.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import org.unifiedpush.distributor.sunup.EventBus - -class UiAction(val action: Action) { - enum class Action { - RefreshRegistrations, - RefreshApiUrl - } - - fun handle(action: (Action) -> Unit) { - action(this.action) - } - - companion object { - fun publish(type: Action) { - CoroutineScope(Dispatchers.IO).launch { - EventBus.publish(UiAction(type)) - } - } - } -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ViewModelFactory.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ViewModelFactory.kt deleted file mode 100644 index c3ed93b..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ViewModelFactory.kt +++ /dev/null @@ -1,50 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities - -import android.app.Application -import android.content.Context -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import org.unifiedpush.android.distributor.ui.compose.BatteryOptimisationViewModel -import org.unifiedpush.android.distributor.ui.compose.previewRegistrationsViewModel -import org.unifiedpush.android.distributor.ui.compose.state.DistribMigrationState -import org.unifiedpush.distributor.sunup.BuildConfig -import org.unifiedpush.distributor.sunup.activities.ThemeViewModel -import org.unifiedpush.distributor.sunup.activities.ui.MainUiState -import org.unifiedpush.distributor.sunup.activities.ui.SettingsState - -class ViewModelFactory(val application: Application) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T = when { - modelClass.isAssignableFrom(MainViewModel::class.java) -> MainViewModel(application) - modelClass.isAssignableFrom(SettingsViewModel::class.java) -> SettingsViewModel( - application - ) - modelClass.isAssignableFrom(ThemeViewModel::class.java) -> ThemeViewModel(application) - modelClass.isAssignableFrom(DistribMigrationViewModel::class.java) -> DistribMigrationViewModel(application) - else -> throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}") - } as T -} - -class PreviewFactory(val context: Context) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T = when { - modelClass.isAssignableFrom(MainViewModel::class.java) -> { - MainViewModel( - MainUiState(), - BatteryOptimisationViewModel(true), - previewRegistrationsViewModel(context) - ) - } - modelClass.isAssignableFrom(SettingsViewModel::class.java) -> { - SettingsViewModel( - SettingsState( - BuildConfig.DEFAULT_API_URL, - false - ) - ) - } - modelClass.isAssignableFrom(ThemeViewModel::class.java) -> ThemeViewModel() - modelClass.isAssignableFrom(DistribMigrationViewModel::class.java) -> { - DistribMigrationViewModel(DistribMigrationState()) - } - else -> throw IllegalArgumentException("Unknown ViewModel class") - } as T -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/AppUi.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/AppUi.kt deleted file mode 100644 index 9a55554..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/AppUi.kt +++ /dev/null @@ -1,159 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities.ui - -import android.annotation.SuppressLint -import androidx.annotation.StringRes -import androidx.compose.animation.EnterTransition -import androidx.compose.animation.ExitTransition -import androidx.compose.animation.core.tween -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.slideInHorizontally -import androidx.compose.animation.slideOutHorizontally -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawing -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.tooling.preview.Preview -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.viewmodel.compose.viewModel -import androidx.navigation.NavHostController -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable -import androidx.navigation.compose.currentBackStackEntryAsState -import androidx.navigation.compose.rememberNavController -import org.unifiedpush.android.distributor.ui.R as LibR -import org.unifiedpush.android.distributor.ui.compose.AppBar -import org.unifiedpush.distributor.sunup.R -import org.unifiedpush.distributor.sunup.activities.DistribMigrationViewModel -import org.unifiedpush.distributor.sunup.activities.MainViewModel -import org.unifiedpush.distributor.sunup.activities.PreviewFactory -import org.unifiedpush.distributor.sunup.activities.SettingsViewModel -import org.unifiedpush.distributor.sunup.activities.ThemeViewModel - -enum class AppScreen(@StringRes val title: Int) { - Main(R.string.app_name), - Settings(LibR.string.settings) -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun DefaultTopBar( - currentScreen: AppScreen, - canNavigateBack: Boolean, - navigateUp: () -> Unit, - modifier: Modifier = Modifier -) = AppBar( - currentScreen.title, - canNavigateBack, - navigateUp, - modifier -) - -private enum class Dir { - Left, - Right -} - -private fun Dir.transform(it: Int): Int = when (this) { - Dir.Left -> it - Dir.Right -> -it -} - -private fun slideInTo(dir: Dir): EnterTransition = slideInHorizontally( - animationSpec = tween(durationMillis = 200) -) { dir.transform(it) } + fadeIn(initialAlpha = 1f) - -private fun slideOutFrom(dir: Dir): ExitTransition = slideOutHorizontally( - animationSpec = tween(durationMillis = 200) -) { dir.transform(it) } + fadeOut(targetAlpha = 1f) - -@Composable -fun App( - factory: ViewModelProvider.Factory, - themeViewModel: ThemeViewModel = viewModel(factory = factory), - navController: NavHostController = rememberNavController() -) { - val backStackEntry by navController.currentBackStackEntryAsState() - val currentScreen = AppScreen.valueOf( - backStackEntry?.destination?.route ?: AppScreen.Main.name - ) - // shared with all views, no need to scope it - val migrationViewModel = viewModel(factory = factory) - val mainViewModel = viewModel(factory = factory) - - Scaffold( - topBar = { - when (currentScreen) { - AppScreen.Main -> { - MainAppBarOrSelection( - mainViewModel, - onGoToSettings = { - navController.navigate(AppScreen.Settings.name) - } - ) - } - else -> null - } ?: DefaultTopBar( - currentScreen, - canNavigateBack = navController.previousBackStackEntry != null, - navigateUp = { navController.navigateUp() } - ) - }, - contentWindowInsets = WindowInsets.safeDrawing - ) { innerPadding -> - NavHost( - navController = navController, - startDestination = AppScreen.Main.name, - modifier = Modifier - .fillMaxSize() - .verticalScroll(rememberScrollState()) - .padding(innerPadding) - ) { - composable( - route = AppScreen.Main.name, - exitTransition = { - when (targetState.destination.route) { - AppScreen.Settings.name -> slideOutFrom( - Dir.Right - ) - else -> fadeOut() - } - }, - popEnterTransition = { - when (initialState.destination.route) { - AppScreen.Settings.name -> slideInTo(Dir.Right) - else -> fadeIn() - } - } - ) { - MainScreen( - mainViewModel, - migrationViewModel - ) - } - composable( - route = AppScreen.Settings.name, - enterTransition = { slideInTo(Dir.Left) }, - popExitTransition = { slideOutFrom(Dir.Left) } - ) { - val vm = viewModel(factory = factory) - SettingsScreen(vm, themeViewModel, migrationViewModel) - } - } - } -} - -@SuppressLint("ViewModelConstructorInComposable") -@Preview -@Composable -fun PreviewApp() = App( - factory = PreviewFactory(LocalContext.current) -) diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/ChangeServerUi.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/ChangeServerUi.kt deleted file mode 100644 index 16a3311..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/ChangeServerUi.kt +++ /dev/null @@ -1,75 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities.ui - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import org.unifiedpush.android.distributor.ui.R -import org.unifiedpush.distributor.sunup.BuildConfig - -@Preview -@Composable -fun ChangeServerUi(currentValue: String = BuildConfig.DEFAULT_API_URL, onValueChange: (String) -> Unit = {}) { - Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { - Text( - stringResource(R.string.push_server) - ) - TextField( - value = currentValue, - onValueChange = onValueChange, - label = { Text(stringResource(R.string.url)) }, - maxLines = 1 - ) - } -} - -@Preview -@Composable -fun ChangeServerDialog( - currentValue: String = BuildConfig.DEFAULT_API_URL, - onDismissRequest: () -> Unit = {}, - onConfirmation: (String) -> Unit = {} -) { - var value by remember { mutableStateOf(currentValue) } - AlertDialog( - title = { - stringResource(R.string.push_server) - }, - text = { - ChangeServerUi(value) { - value = it - } - }, - onDismissRequest = { - onDismissRequest() - }, - confirmButton = { - TextButton( - onClick = { - onConfirmation(value) - } - ) { - Text(stringResource(android.R.string.ok)) - } - }, - dismissButton = { - TextButton( - onClick = { - onDismissRequest() - } - ) { - Text(stringResource(android.R.string.cancel)) - } - } - ) -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/MainScreen.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/MainScreen.kt deleted file mode 100644 index 25eb8b8..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/MainScreen.kt +++ /dev/null @@ -1,230 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities.ui - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.text.selection.SelectionContainer -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.MoreVert -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -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.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.compose.LocalLifecycleOwner -import androidx.lifecycle.repeatOnLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel -import org.unifiedpush.android.distributor.ui.R as LibR -import org.unifiedpush.android.distributor.ui.compose.AppBar -import org.unifiedpush.android.distributor.ui.compose.CardDisableBatteryOptimisation -import org.unifiedpush.android.distributor.ui.compose.CardDisabledForMigration -import org.unifiedpush.android.distributor.ui.compose.DistribMigrationUi -import org.unifiedpush.android.distributor.ui.compose.PermissionsUi -import org.unifiedpush.android.distributor.ui.compose.RegistrationList -import org.unifiedpush.android.distributor.ui.compose.RegistrationListHeading -import org.unifiedpush.android.distributor.ui.compose.UnregisterBarUi -import org.unifiedpush.distributor.sunup.EventBus -import org.unifiedpush.distributor.sunup.R -import org.unifiedpush.distributor.sunup.activities.DistribMigrationViewModel -import org.unifiedpush.distributor.sunup.activities.MainViewModel -import org.unifiedpush.distributor.sunup.activities.PreviewFactory -import org.unifiedpush.distributor.sunup.activities.UiAction -import org.unifiedpush.distributor.sunup.utils.getDebugInfo - -@Composable -fun MainAppBarOrSelection(viewModel: MainViewModel, onGoToSettings: () -> Unit) { - val registrationsState = viewModel.registrationsViewModel.state - if (registrationsState.selectionCount > 0) { - UnregisterBarUi( - viewModel = viewModel.registrationsViewModel, - onDelete = { viewModel.deleteSelection() } - ) - } else { - MainAppBar( - viewModel, - onGoToSettings - ) - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun MainAppBar(viewModel: MainViewModel, onGoToSettings: () -> Unit) { - var openMenu by remember { mutableStateOf(false) } - - AppBar( - R.string.app_name, - false, - {}, - actions = { - IconButton( - onClick = { - openMenu = true - } - ) { - Icon( - imageVector = Icons.Default.MoreVert, - contentDescription = stringResource(LibR.string.app_bar_dropdown_description) - ) - } - Dropdown( - openMenu, - onRestart = { - viewModel.restartService() - openMenu = false - }, - onDismiss = { - openMenu = false - }, - onGoToSettings = onGoToSettings - ) - } - ) -} - -@Composable -fun Dropdown( - expanded: Boolean, - onRestart: () -> Unit, - onDismiss: () -> Unit, - onGoToSettings: () -> Unit -) { - DropdownMenu( - expanded = expanded, - onDismissRequest = onDismiss - ) { - DropdownMenuItem( - onClick = onRestart, - text = { - Text(stringResource(LibR.string.app_dropdown_restart)) - } - ) - DropdownMenuItem( - onClick = onGoToSettings, - text = { - Text(stringResource(LibR.string.settings)) - } - ) - } -} - -@Composable -fun MainScreen(viewModel: MainViewModel, migrationViewModel: DistribMigrationViewModel) { - val lifecycleOwner = LocalLifecycleOwner.current - LaunchedEffect(Unit) { - EventBus.subscribe { - it.handle { type -> - when (type) { - UiAction.Action.RefreshRegistrations -> viewModel.refreshRegistrations() - else -> {} - } - } - } - } - LaunchedEffect(Unit) { - lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { - viewModel.refreshRegistrations() - } - } - Column( - modifier = Modifier - .fillMaxSize(), - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.spacedBy(2.dp) - ) { - Column( - modifier = Modifier - .padding(horizontal = 16.dp), - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - Spacer(Modifier) - - if (migrationViewModel.state.migrated) { - CardDisabledForMigration { - migrationViewModel.reactivateUnifiedPush() - } - return - } - - CardDisableBatteryOptimisation(viewModel.batteryOptimisationViewModel) - - RegistrationListHeading( - modifier = Modifier.clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { - viewModel.addDebugClick() - } - ) - } - - RegistrationList(viewModel.registrationsViewModel) { - // We don't have copyable endpoint - } - } - if (viewModel.mainUiState.showPermissionDialog) { - PermissionsUi { - viewModel.closePermissionDialog() - migrationViewModel.mayShowFallbackIntro() - } - } - if (viewModel.mainUiState.showDebugInfo) { - DebugDialog { - viewModel.dismissDebugInfo() - } - } - if (migrationViewModel.state.showMigrations) { - DistribMigrationUi(migrationViewModel) - } -} - -@Composable -fun DebugDialog(onDismissRequest: () -> Unit) { - val text = getDebugInfo() - AlertDialog( - title = { Text("Debug") }, - text = { - SelectionContainer { - Text(text) - } - }, - onDismissRequest = onDismissRequest, - confirmButton = { - TextButton( - onClick = onDismissRequest - ) { - Text(stringResource(android.R.string.ok)) - } - } - ) -} - -@Preview -@Composable -fun MainPreview() { - val factory = PreviewFactory(LocalContext.current) - val mainVM = viewModel(factory = factory) - val migrationVM = viewModel(factory = factory) - MainScreen(mainVM, migrationVM) -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/MainUiState.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/MainUiState.kt deleted file mode 100644 index a3a4cd2..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/MainUiState.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities.ui - -data class MainUiState(val showDebugInfo: Boolean = false, val showPermissionDialog: Boolean = true) diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/PrivacyPolicyDialogUi.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/PrivacyPolicyDialogUi.kt deleted file mode 100644 index 60eda56..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/PrivacyPolicyDialogUi.kt +++ /dev/null @@ -1,56 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities.ui - -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.LinkAnnotation -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextLinkStyles -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.withLink -import androidx.compose.ui.tooling.preview.Preview -import org.unifiedpush.android.distributor.ui.R as LibR -import org.unifiedpush.distributor.sunup.R - -@Composable -fun PrivacyPolicyDialog(onDismiss: () -> Unit) { - AlertDialog( - title = { - Text(stringResource(LibR.string.privacy_policy)) - }, - text = { - PrivacyPolicy() - }, - onDismissRequest = onDismiss, - confirmButton = { - TextButton( - onClick = onDismiss - ) { - Text(stringResource(android.R.string.cancel)) - } - } - - ) -} - -@Preview -@Composable -private fun PrivacyPolicy() { - Text( - buildAnnotatedString { - append(stringResource(R.string.sunup_privacy_policy).format(stringResource(R.string.app_name))) - - withLink( - LinkAnnotation.Url( - "https://www.mozilla.org/en-US/privacy/firefox/#types-of-data-defined", - TextLinkStyles(style = SpanStyle(color = MaterialTheme.colorScheme.primary)) - ) - ) { - append("https://www.mozilla.org/en-US/privacy/firefox/") - } - } - ) -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/SettingsScreen.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/SettingsScreen.kt deleted file mode 100644 index ae49949..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/SettingsScreen.kt +++ /dev/null @@ -1,121 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities.ui - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.compose.LocalLifecycleOwner -import androidx.lifecycle.repeatOnLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel -import org.unifiedpush.android.distributor.ui.R as LibR -import org.unifiedpush.android.distributor.ui.compose.AboutHeading -import org.unifiedpush.android.distributor.ui.compose.DistribMigrationUi -import org.unifiedpush.android.distributor.ui.compose.DynamicColorsPreferences -import org.unifiedpush.android.distributor.ui.compose.Heading -import org.unifiedpush.android.distributor.ui.compose.MigrationPreferences -import org.unifiedpush.android.distributor.ui.compose.Preference -import org.unifiedpush.android.distributor.ui.compose.ShowToastsPreference -import org.unifiedpush.distributor.sunup.EventBus -import org.unifiedpush.distributor.sunup.R -import org.unifiedpush.distributor.sunup.activities.DistribMigrationViewModel -import org.unifiedpush.distributor.sunup.activities.PreviewFactory -import org.unifiedpush.distributor.sunup.activities.SettingsViewModel -import org.unifiedpush.distributor.sunup.activities.ThemeViewModel -import org.unifiedpush.distributor.sunup.activities.UiAction - -@Composable -fun SettingsScreen( - viewModel: SettingsViewModel, - themeViewModel: ThemeViewModel, - migrationViewModel: DistribMigrationViewModel -) { - val state = viewModel.state - val lifecycleOwner = LocalLifecycleOwner.current - LaunchedEffect(Unit) { - EventBus.subscribe { - it.handle { type -> - when (type) { - UiAction.Action.RefreshApiUrl -> viewModel.refreshApiUrl() - else -> {} - } - } - } - } - LaunchedEffect(Unit) { - lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { - viewModel.refreshApiUrl() - migrationViewModel.refreshDistributors() - } - } - Column( - modifier = Modifier - .padding(16.dp), - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.spacedBy(20.dp) - ) { - Heading(R.string.app_name) - - Preference( - stringResource(LibR.string.push_server), - stringResource(LibR.string.clicklabel_select_push_server), - state.currentApiUrl, - onSelect = { - viewModel.toggleChangeServer() - } - ) - - ShowToastsPreference(viewModel.state.showToasts) { - viewModel.toggleShowToasts() - } - - DynamicColorsPreferences(themeViewModel.dynamicColors) { - themeViewModel.toggleDynamicColors() - } - - MigrationPreferences(migrationViewModel) - - AboutHeading() - - Preference( - stringResource(LibR.string.privacy_policy), - stringResource(LibR.string.open_privacy_policy_clicklabel), - onSelect = { - viewModel.togglePrivacyPolicy() - } - ) - } - - if (state.showChangeServerDialog) { - ChangeServerDialog( - state.currentApiUrl, - onDismissRequest = { viewModel.toggleChangeServer() }, - onConfirmation = { viewModel.newPushServer(it) } - ) - } - if (state.showPrivacyPolicy) { - PrivacyPolicyDialog { - viewModel.togglePrivacyPolicy() - } - } - if (migrationViewModel.state.showMigrations) { - DistribMigrationUi(migrationViewModel) - } -} - -@Preview -@Composable -fun PreviewSettingsScreen() { - val factory = PreviewFactory(LocalContext.current) - val settVM = viewModel(factory = factory) - val themeVM = viewModel(factory = factory) - val migrationVM = viewModel(factory = factory) - SettingsScreen(settVM, themeVM, migrationVM) -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/SettingsState.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/SettingsState.kt deleted file mode 100644 index 963db32..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/activities/ui/SettingsState.kt +++ /dev/null @@ -1,21 +0,0 @@ -package org.unifiedpush.distributor.sunup.activities.ui - -import android.content.Context -import org.unifiedpush.distributor.sunup.AppStore - -data class SettingsState( - val currentApiUrl: String, - val showToasts: Boolean, - val showChangeServerDialog: Boolean = false, - val showPrivacyPolicy: Boolean = false -) { - companion object { - fun from(context: Context): SettingsState { - val store = AppStore(context) - return SettingsState( - store.apiUrl, - store.showToasts - ) - } - } -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/api/ServerConnection.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/api/ServerConnection.kt index b70d85e..d30c3b6 100644 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/api/ServerConnection.kt +++ b/app/src/main/java/org/unifiedpush/distributor/sunup/api/ServerConnection.kt @@ -16,11 +16,12 @@ import okhttp3.WebSocket import okhttp3.WebSocketListener import org.unifiedpush.android.distributor.ui.R as LibR import org.unifiedpush.distributor.ChannelCreationStatus +import org.unifiedpush.distributor.ipc.ACTION_REFRESH_API_URL +import org.unifiedpush.distributor.ipc.sendUiAction import org.unifiedpush.distributor.sunup.AppStore import org.unifiedpush.distributor.sunup.DatabaseFactory import org.unifiedpush.distributor.sunup.Distributor import org.unifiedpush.distributor.sunup.Distributor.sendMessage -import org.unifiedpush.distributor.sunup.activities.UiAction import org.unifiedpush.distributor.sunup.api.data.ClientMessage import org.unifiedpush.distributor.sunup.api.data.ServerMessage import org.unifiedpush.distributor.sunup.callback.NetworkCallbackFactory @@ -202,7 +203,7 @@ class ServerConnection(private val context: Context, private val releaseLock: () Toast.LENGTH_SHORT ).show() } - UiAction.publish(UiAction.Action.RefreshApiUrl) + sendUiAction(context, ACTION_REFRESH_API_URL) RestartWorker.run(context, delay = 0) return true } diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/services/InternalServiceImpl.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/services/InternalServiceImpl.kt new file mode 100644 index 0000000..4454579 --- /dev/null +++ b/app/src/main/java/org/unifiedpush/distributor/sunup/services/InternalServiceImpl.kt @@ -0,0 +1,80 @@ +package org.unifiedpush.distributor.sunup.services + +import android.os.Bundle +import java.text.SimpleDateFormat +import org.unifiedpush.distributor.Database +import org.unifiedpush.distributor.MigrationManager +import org.unifiedpush.distributor.SourceManager +import org.unifiedpush.distributor.UnifiedPushDistributor +import org.unifiedpush.distributor.WorkerCompanion +import org.unifiedpush.distributor.ipc.ACTION_REFRESH_API_URL +import org.unifiedpush.distributor.ipc.handler.IAccount +import org.unifiedpush.distributor.ipc.handler.IApi +import org.unifiedpush.distributor.ipc.sendUiAction +import org.unifiedpush.distributor.service.ForegroundServiceFactory +import org.unifiedpush.distributor.service.InternalService +import org.unifiedpush.distributor.sunup.AppStore +import org.unifiedpush.distributor.sunup.BuildConfig +import org.unifiedpush.distributor.sunup.DatabaseFactory +import org.unifiedpush.distributor.sunup.Distributor +import org.unifiedpush.distributor.sunup.api.ApiUrlCandidate +import org.unifiedpush.distributor.sunup.api.ServerConnection + +class InternalServiceImpl : InternalService() { + override val sourceManager: SourceManager<*> + get() = SourceManager + override val restartWorker: WorkerCompanion + get() = RestartWorker.Companion + override val startService: ForegroundServiceFactory + get() = FgService.Companion + override val migrationManager: MigrationManager + get() = MigrationManagerImpl() + override val distributor: UnifiedPushDistributor + get() = Distributor + override val db: Database + get() = DatabaseFactory.getDb(this) + + override fun getDebugInfo(): String { + val date = ServerConnection.lastEventDate?.let { + SimpleDateFormat.getDateTimeInstance().format(it.time) + } ?: "None" + return "ServiceStarted: ${FgService.isServiceStarted()}\n" + + "Last Event: $date\n" + + org.unifiedpush.distributor.sunup.services.SourceManager.getDebugInfo() + } + + /** + * Not used by Sunup + */ + override fun account() = object : IAccount { + override fun get(): String? = null + override fun logout() {} + override fun login(data: Bundle) {} + } + + override fun api() = object : IApi { + override fun newPushServer(url: String?) { + url?.let { + ApiUrlCandidate.test(context, url) + } ?: run { + AppStore(context).apiUrl = BuildConfig.DEFAULT_API_URL + restartWorker().restart() + sendUiAction(context, ACTION_REFRESH_API_URL) + } + } + + override fun getUrl() = AppStore(context).apiUrl + } + + override var themeDynamicColors: Boolean + get() = AppStore(context).dynamicColors + set(value) { + AppStore(context).dynamicColors = value + } + + override var showToasts: Boolean + get() = AppStore(context).showToasts + set(value) { + AppStore(context).showToasts = value + } +} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/services/MainRegistrationCounter.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/services/MainRegistrationCounter.kt index c9143cc..e6973df 100644 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/services/MainRegistrationCounter.kt +++ b/app/src/main/java/org/unifiedpush/distributor/sunup/services/MainRegistrationCounter.kt @@ -3,8 +3,8 @@ package org.unifiedpush.distributor.sunup.services import android.content.Context import org.unifiedpush.distributor.Database import org.unifiedpush.distributor.RegistrationCounter +import org.unifiedpush.distributor.ipc.sendUiAction import org.unifiedpush.distributor.sunup.DatabaseFactory -import org.unifiedpush.distributor.sunup.activities.UiAction import org.unifiedpush.distributor.sunup.utils.ForegroundNotification object MainRegistrationCounter : RegistrationCounter() { @@ -15,7 +15,7 @@ object MainRegistrationCounter : RegistrationCounter() { override fun onCountRefreshed(context: Context) { ForegroundNotification(context).update() - UiAction.publish(UiAction.Action.RefreshRegistrations) + sendUiAction(context, "REFRESH_REGISTRATIONS") } override fun getDb(context: Context): Database = DatabaseFactory.getDb(context) diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/services/MigrationManager.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/services/MigrationManagerImpl.kt similarity index 75% rename from app/src/main/java/org/unifiedpush/distributor/sunup/services/MigrationManager.kt rename to app/src/main/java/org/unifiedpush/distributor/sunup/services/MigrationManagerImpl.kt index c6fd71c..8a7245f 100644 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/services/MigrationManager.kt +++ b/app/src/main/java/org/unifiedpush/distributor/sunup/services/MigrationManagerImpl.kt @@ -1,11 +1,11 @@ package org.unifiedpush.distributor.sunup.services import android.content.Context -import org.unifiedpush.distributor.MigrationManager as MManager +import org.unifiedpush.distributor.MigrationManager import org.unifiedpush.distributor.sunup.AppStore import org.unifiedpush.distributor.sunup.Distributor -class MigrationManager : MManager() { +class MigrationManagerImpl : MigrationManager() { override val distrib = Distributor override fun getStore(context: Context): MigrationStore = AppStore(context) } diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/services/SourceManager.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/services/SourceManager.kt index 5b8323a..72dab27 100644 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/services/SourceManager.kt +++ b/app/src/main/java/org/unifiedpush/distributor/sunup/services/SourceManager.kt @@ -10,7 +10,7 @@ import org.unifiedpush.distributor.sunup.utils.DisconnectedNotification object SourceManager : SManager() { override val foregroundService = FgService.service - override val migrationManager = MigrationManager() + override val migrationManager = MigrationManagerImpl() override fun disconnectedNotification(context: Context): AppNotification = DisconnectedNotification(context) diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/utils/DebugInformation.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/utils/DebugInformation.kt deleted file mode 100644 index 80fb2a7..0000000 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/utils/DebugInformation.kt +++ /dev/null @@ -1,15 +0,0 @@ -package org.unifiedpush.distributor.sunup.utils - -import java.text.SimpleDateFormat -import org.unifiedpush.distributor.sunup.api.ServerConnection -import org.unifiedpush.distributor.sunup.services.FgService -import org.unifiedpush.distributor.sunup.services.SourceManager - -fun getDebugInfo(): String { - val date = ServerConnection.lastEventDate?.let { - SimpleDateFormat.getDateTimeInstance().format(it.time) - } ?: "None" - return "ServiceStarted: ${FgService.isServiceStarted()}\n" + - "Last Event: $date\n" + - SourceManager.getDebugInfo() -} diff --git a/app/src/main/java/org/unifiedpush/distributor/sunup/utils/Notifications.kt b/app/src/main/java/org/unifiedpush/distributor/sunup/utils/Notifications.kt index fb00e8d..6244442 100644 --- a/app/src/main/java/org/unifiedpush/distributor/sunup/utils/Notifications.kt +++ b/app/src/main/java/org/unifiedpush/distributor/sunup/utils/Notifications.kt @@ -7,7 +7,6 @@ import java.util.concurrent.atomic.AtomicBoolean import org.unifiedpush.android.distributor.ui.R as LibR import org.unifiedpush.distributor.AppNotification import org.unifiedpush.distributor.sunup.R -import org.unifiedpush.distributor.sunup.activities.MainActivity import org.unifiedpush.distributor.sunup.services.MainRegistrationCounter const val NOTIFICATION_ID_FOREGROUND = 51115 @@ -25,8 +24,7 @@ class MainNotificationData( text = text, ticker = ticker, priority = priority, - ongoing = ongoing, - activity = MainActivity::class.java + ongoing = ongoing ) private val Context.warningChannelData: AppNotification.ChannelData