mirror of
https://github.com/lone-cloud/prism-android
synced 2026-06-03 19:54:44 -07:00
Use new UI from library
This commit is contained in:
parent
9c39c0ad6e
commit
1ae48fdfc1
27 changed files with 154 additions and 1193 deletions
|
|
@ -21,6 +21,7 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.MainActivity"
|
android:name=".activities.MainActivity"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
|
android:process=":ui"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
@ -34,6 +35,12 @@
|
||||||
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||||
android:value="This service needs to be constantly connected to the server, to get Server-Sent Events messages from it."/>
|
android:value="This service needs to be constantly connected to the server, to get Server-Sent Events messages from it."/>
|
||||||
</service>
|
</service>
|
||||||
|
<service android:name=".services.InternalServiceImpl"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.unifiedpush.distributor.internal.service"/>
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".receivers.StartReceiver"
|
android:name=".receivers.StartReceiver"
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@ import org.unifiedpush.distributor.Database
|
||||||
import org.unifiedpush.distributor.UnifiedPushDistributor
|
import org.unifiedpush.distributor.UnifiedPushDistributor
|
||||||
import org.unifiedpush.distributor.sunup.api.MessageSender
|
import org.unifiedpush.distributor.sunup.api.MessageSender
|
||||||
import org.unifiedpush.distributor.sunup.api.data.ClientMessage
|
import org.unifiedpush.distributor.sunup.api.data.ClientMessage
|
||||||
|
import org.unifiedpush.distributor.sunup.receivers.RegisterBroadcastReceiver
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These functions are used to send messages to other apps
|
* These functions are used to send messages to other apps
|
||||||
*/
|
*/
|
||||||
object Distributor : UnifiedPushDistributor() {
|
object Distributor : UnifiedPushDistributor() {
|
||||||
override val receiverComponentName = "org.unifiedpush.distributor.sunup.receivers.RegisterBroadcastReceiver"
|
override val receiverComponent = RegisterBroadcastReceiver::class.java
|
||||||
|
|
||||||
override fun getDb(context: Context): Database = DatabaseFactory.getDb(context)
|
override fun getDb(context: Context): Database = DatabaseFactory.getDb(context)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.unifiedpush.distributor.sunup
|
||||||
|
|
||||||
|
import org.unifiedpush.android.distributor.ui.AppConfig
|
||||||
|
import org.unifiedpush.android.distributor.ui.InAppNotifsConfig
|
||||||
|
import org.unifiedpush.android.distributor.ui.LoginConfig
|
||||||
|
import org.unifiedpush.android.distributor.ui.MigrationConfig
|
||||||
|
import org.unifiedpush.android.distributor.ui.NoLoginConfig
|
||||||
|
import org.unifiedpush.android.distributor.ui.PrivacyPolicy
|
||||||
|
|
||||||
|
class SunupAppConfig : AppConfig {
|
||||||
|
override val appName: Int
|
||||||
|
get() = R.string.app_name
|
||||||
|
override val restartableService = true
|
||||||
|
override val privacyPolicy: PrivacyPolicy
|
||||||
|
get() = object : PrivacyPolicy {
|
||||||
|
override val description: Int
|
||||||
|
get() = R.string.sunup_privacy_policy
|
||||||
|
override val linkText: String
|
||||||
|
get() = "https://www.mozilla.org/en-US/privacy/firefox/"
|
||||||
|
override val linkTarget: String
|
||||||
|
get() = "https://www.mozilla.org/en-US/privacy/firefox/#types-of-data-defined"
|
||||||
|
}
|
||||||
|
override val loginConfig: LoginConfig
|
||||||
|
get() = NoLoginConfig(canChangeUrl = true)
|
||||||
|
override val migrationConfig: MigrationConfig?
|
||||||
|
get() = if (BuildConfig.SUPPORT_MIGRATIONS) {
|
||||||
|
object : MigrationConfig {
|
||||||
|
override val supportTempFallback = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
override val inAppNotifsConfig: InAppNotifsConfig? = null
|
||||||
|
}
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
package org.unifiedpush.distributor.sunup.activities
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.unifiedpush.distributor.sunup.AppStore
|
|
||||||
import org.unifiedpush.distributor.sunup.Distributor
|
|
||||||
import org.unifiedpush.distributor.sunup.EventBus
|
|
||||||
import org.unifiedpush.distributor.sunup.api.ApiUrlCandidate
|
|
||||||
import org.unifiedpush.distributor.sunup.services.FgService
|
|
||||||
import org.unifiedpush.distributor.sunup.services.MigrationManager
|
|
||||||
import org.unifiedpush.distributor.sunup.services.RestartWorker
|
|
||||||
import org.unifiedpush.distributor.sunup.services.SourceManager
|
|
||||||
import org.unifiedpush.distributor.sunup.utils.TAG
|
|
||||||
|
|
||||||
class AppAction(private val action: Action) {
|
|
||||||
sealed class Action {
|
|
||||||
data object RestartService : Action()
|
|
||||||
class NewPushServer(val url: String) : Action()
|
|
||||||
class ShowToasts(val enable: Boolean) : Action()
|
|
||||||
class DeleteRegistration(val registrations: List<String>) : 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,53 +6,51 @@ import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlin.system.exitProcess
|
||||||
import kotlinx.coroutines.Dispatchers
|
import org.unifiedpush.android.distributor.ui.screen.App
|
||||||
import kotlinx.coroutines.Job
|
import org.unifiedpush.android.distributor.ui.vm.ThemeViewModel
|
||||||
import kotlinx.coroutines.launch
|
import org.unifiedpush.android.distributor.ui.vm.ViewModelFactory
|
||||||
import org.unifiedpush.distributor.sunup.EventBus
|
import org.unifiedpush.distributor.ipc.InternalMessenger
|
||||||
|
import org.unifiedpush.distributor.ipc.subscribeUiActions
|
||||||
import org.unifiedpush.distributor.sunup.Migrations
|
import org.unifiedpush.distributor.sunup.Migrations
|
||||||
import org.unifiedpush.distributor.sunup.activities.ThemeViewModel
|
import org.unifiedpush.distributor.sunup.SunupAppConfig
|
||||||
import org.unifiedpush.distributor.sunup.activities.ui.App
|
|
||||||
import org.unifiedpush.distributor.sunup.activities.ui.theme.AppTheme
|
import org.unifiedpush.distributor.sunup.activities.ui.theme.AppTheme
|
||||||
import org.unifiedpush.distributor.sunup.services.RestartWorker
|
|
||||||
import org.unifiedpush.distributor.sunup.utils.TAG
|
import org.unifiedpush.distributor.sunup.utils.TAG
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
private var jobs: MutableList<Job> = emptyList<Job>().toMutableList()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
RestartWorker.startPeriodic(this)
|
|
||||||
Migrations(this).run()
|
Migrations(this).run()
|
||||||
|
val messenger = InternalMessenger(this)
|
||||||
|
val uiFlow = subscribeUiActions(this)
|
||||||
|
val appConfig = SunupAppConfig()
|
||||||
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
val factory = ViewModelFactory(this.application)
|
val factory = ViewModelFactory(
|
||||||
|
context = this,
|
||||||
|
appConfig = appConfig,
|
||||||
|
messenger = messenger
|
||||||
|
)
|
||||||
val themeViewModel = viewModel<ThemeViewModel>(factory = factory)
|
val themeViewModel = viewModel<ThemeViewModel>(factory = factory)
|
||||||
AppTheme(
|
AppTheme(
|
||||||
dynamicColor = themeViewModel.dynamicColors
|
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<AppAction> { it.handle(this@MainActivity) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
Log.d(TAG, "Destroy")
|
Log.d(TAG, "Destroy")
|
||||||
jobs.removeAll {
|
|
||||||
it.cancel()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
)
|
|
||||||
|
|
@ -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)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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 <T : ViewModel> create(modelClass: Class<T>): 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 <T : ViewModel> create(modelClass: Class<T>): 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
|
|
||||||
}
|
|
||||||
|
|
@ -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<ThemeViewModel>(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<DistribMigrationViewModel>(factory = factory)
|
|
||||||
val mainViewModel = viewModel<MainViewModel>(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<SettingsViewModel>(factory = factory)
|
|
||||||
SettingsScreen(vm, themeViewModel, migrationViewModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ViewModelConstructorInComposable")
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun PreviewApp() = App(
|
|
||||||
factory = PreviewFactory(LocalContext.current)
|
|
||||||
)
|
|
||||||
|
|
@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -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<UiAction> {
|
|
||||||
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<MainViewModel>(factory = factory)
|
|
||||||
val migrationVM = viewModel<DistribMigrationViewModel>(factory = factory)
|
|
||||||
MainScreen(mainVM, migrationVM)
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
package org.unifiedpush.distributor.sunup.activities.ui
|
|
||||||
|
|
||||||
data class MainUiState(val showDebugInfo: Boolean = false, val showPermissionDialog: Boolean = true)
|
|
||||||
|
|
@ -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/")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -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<UiAction> {
|
|
||||||
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<SettingsViewModel>(factory = factory)
|
|
||||||
val themeVM = viewModel<ThemeViewModel>(factory = factory)
|
|
||||||
val migrationVM = viewModel<DistribMigrationViewModel>(factory = factory)
|
|
||||||
SettingsScreen(settVM, themeVM, migrationVM)
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -16,11 +16,12 @@ import okhttp3.WebSocket
|
||||||
import okhttp3.WebSocketListener
|
import okhttp3.WebSocketListener
|
||||||
import org.unifiedpush.android.distributor.ui.R as LibR
|
import org.unifiedpush.android.distributor.ui.R as LibR
|
||||||
import org.unifiedpush.distributor.ChannelCreationStatus
|
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.AppStore
|
||||||
import org.unifiedpush.distributor.sunup.DatabaseFactory
|
import org.unifiedpush.distributor.sunup.DatabaseFactory
|
||||||
import org.unifiedpush.distributor.sunup.Distributor
|
import org.unifiedpush.distributor.sunup.Distributor
|
||||||
import org.unifiedpush.distributor.sunup.Distributor.sendMessage
|
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.ClientMessage
|
||||||
import org.unifiedpush.distributor.sunup.api.data.ServerMessage
|
import org.unifiedpush.distributor.sunup.api.data.ServerMessage
|
||||||
import org.unifiedpush.distributor.sunup.callback.NetworkCallbackFactory
|
import org.unifiedpush.distributor.sunup.callback.NetworkCallbackFactory
|
||||||
|
|
@ -202,7 +203,7 @@ class ServerConnection(private val context: Context, private val releaseLock: ()
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
UiAction.publish(UiAction.Action.RefreshApiUrl)
|
sendUiAction(context, ACTION_REFRESH_API_URL)
|
||||||
RestartWorker.run(context, delay = 0)
|
RestartWorker.run(context, delay = 0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,8 +3,8 @@ package org.unifiedpush.distributor.sunup.services
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import org.unifiedpush.distributor.Database
|
import org.unifiedpush.distributor.Database
|
||||||
import org.unifiedpush.distributor.RegistrationCounter
|
import org.unifiedpush.distributor.RegistrationCounter
|
||||||
|
import org.unifiedpush.distributor.ipc.sendUiAction
|
||||||
import org.unifiedpush.distributor.sunup.DatabaseFactory
|
import org.unifiedpush.distributor.sunup.DatabaseFactory
|
||||||
import org.unifiedpush.distributor.sunup.activities.UiAction
|
|
||||||
import org.unifiedpush.distributor.sunup.utils.ForegroundNotification
|
import org.unifiedpush.distributor.sunup.utils.ForegroundNotification
|
||||||
|
|
||||||
object MainRegistrationCounter : RegistrationCounter() {
|
object MainRegistrationCounter : RegistrationCounter() {
|
||||||
|
|
@ -15,7 +15,7 @@ object MainRegistrationCounter : RegistrationCounter() {
|
||||||
|
|
||||||
override fun onCountRefreshed(context: Context) {
|
override fun onCountRefreshed(context: Context) {
|
||||||
ForegroundNotification(context).update()
|
ForegroundNotification(context).update()
|
||||||
UiAction.publish(UiAction.Action.RefreshRegistrations)
|
sendUiAction(context, "REFRESH_REGISTRATIONS")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDb(context: Context): Database = DatabaseFactory.getDb(context)
|
override fun getDb(context: Context): Database = DatabaseFactory.getDb(context)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
package org.unifiedpush.distributor.sunup.services
|
package org.unifiedpush.distributor.sunup.services
|
||||||
|
|
||||||
import android.content.Context
|
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.AppStore
|
||||||
import org.unifiedpush.distributor.sunup.Distributor
|
import org.unifiedpush.distributor.sunup.Distributor
|
||||||
|
|
||||||
class MigrationManager : MManager() {
|
class MigrationManagerImpl : MigrationManager() {
|
||||||
override val distrib = Distributor
|
override val distrib = Distributor
|
||||||
override fun getStore(context: Context): MigrationStore = AppStore(context)
|
override fun getStore(context: Context): MigrationStore = AppStore(context)
|
||||||
}
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ import org.unifiedpush.distributor.sunup.utils.DisconnectedNotification
|
||||||
|
|
||||||
object SourceManager : SManager<WebSocket>() {
|
object SourceManager : SManager<WebSocket>() {
|
||||||
override val foregroundService = FgService.service
|
override val foregroundService = FgService.service
|
||||||
override val migrationManager = MigrationManager()
|
override val migrationManager = MigrationManagerImpl()
|
||||||
|
|
||||||
override fun disconnectedNotification(context: Context): AppNotification = DisconnectedNotification(context)
|
override fun disconnectedNotification(context: Context): AppNotification = DisconnectedNotification(context)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,6 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import org.unifiedpush.android.distributor.ui.R as LibR
|
import org.unifiedpush.android.distributor.ui.R as LibR
|
||||||
import org.unifiedpush.distributor.AppNotification
|
import org.unifiedpush.distributor.AppNotification
|
||||||
import org.unifiedpush.distributor.sunup.R
|
import org.unifiedpush.distributor.sunup.R
|
||||||
import org.unifiedpush.distributor.sunup.activities.MainActivity
|
|
||||||
import org.unifiedpush.distributor.sunup.services.MainRegistrationCounter
|
import org.unifiedpush.distributor.sunup.services.MainRegistrationCounter
|
||||||
|
|
||||||
const val NOTIFICATION_ID_FOREGROUND = 51115
|
const val NOTIFICATION_ID_FOREGROUND = 51115
|
||||||
|
|
@ -25,8 +24,7 @@ class MainNotificationData(
|
||||||
text = text,
|
text = text,
|
||||||
ticker = ticker,
|
ticker = ticker,
|
||||||
priority = priority,
|
priority = priority,
|
||||||
ongoing = ongoing,
|
ongoing = ongoing
|
||||||
activity = MainActivity::class.java
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private val Context.warningChannelData: AppNotification.ChannelData
|
private val Context.warningChannelData: AppNotification.ChannelData
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue