Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/src/main/java/com/chiller3/basicsync/Notifications.kt
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class Notifications(private val context: Context) {
setOngoing(true)
setOnlyAlertOnce(true)

if (runState.showFolderStates) {
if (state.showDetails && runState.showFolderStates) {
setContentText(buildString {
append(context.resources.getQuantityString(
R.plurals.device_state_connected,
Expand Down
15 changes: 10 additions & 5 deletions app/src/main/java/com/chiller3/basicsync/Preferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ class Preferences(context: Context) {
const val PREF_RESPECT_BATTERY_SAVER = "respect_battery_saver"
const val PREF_RESPECT_AUTO_SYNC_DATA = "respect_auto_sync_data"
const val PREF_KEEP_ALIVE = "keep_alive"
const val PREF_SHOW_DETAILS = "show_details"
const val PREF_SHOW_EXIT = "show_exit"
const val PREF_REMOTE_CONTROL = "remote_control"
const val PREF_ALLOW_AUTO_MODE = "allow_auto_mode"
const val PREF_SHOW_EXIT = "show_exit"
const val PREF_START_ON_BOOT = "start_on_boot"
const val PREF_REQUIRE_UNMETERED_NETWORK = "require_unmetered_network"
const val PREF_NETWORK_ALLOW_WIFI = "network_allow_wifi"
Expand Down Expand Up @@ -74,6 +75,14 @@ class Preferences(context: Context) {
get() = prefs.getBoolean(PREF_KEEP_ALIVE, true)
set(enabled) = prefs.edit { putBoolean(PREF_KEEP_ALIVE, enabled) }

var showDetails: Boolean
get() = prefs.getBoolean(PREF_SHOW_DETAILS, true)
set(enabled) = prefs.edit { putBoolean(PREF_SHOW_DETAILS, enabled) }

var showExit: Boolean
get() = prefs.getBoolean(PREF_SHOW_EXIT, false)
set(enabled) = prefs.edit { putBoolean(PREF_SHOW_EXIT, enabled) }

var remoteControl: Boolean
get() = prefs.getBoolean(PREF_REMOTE_CONTROL, false)
set(enabled) = prefs.edit { putBoolean(PREF_REMOTE_CONTROL, enabled) }
Expand All @@ -82,10 +91,6 @@ class Preferences(context: Context) {
get() = prefs.getBoolean(PREF_ALLOW_AUTO_MODE, true)
set(enabled) = prefs.edit { putBoolean(PREF_ALLOW_AUTO_MODE, enabled) }

var showExit: Boolean
get() = prefs.getBoolean(PREF_SHOW_EXIT, false)
set(enabled) = prefs.edit { putBoolean(PREF_SHOW_EXIT, enabled) }

var startOnBoot: Boolean
get() = prefs.getBoolean(PREF_START_ON_BOOT, true)
set(enabled) = prefs.edit { putBoolean(PREF_START_ON_BOOT, enabled) }
Expand Down
71 changes: 50 additions & 21 deletions app/src/main/java/com/chiller3/basicsync/settings/SettingsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,10 @@ fun SettingsScreen(
val respectBatterySaver = remember(reloadPrefs) { prefs.respectBatterySaver }
val respectAutoSyncData = remember(reloadPrefs) { prefs.respectAutoSyncData }
val keepAlive = remember(reloadPrefs) { prefs.keepAlive }
val showDetails = remember(reloadPrefs) { prefs.showDetails }
val showExit = remember(reloadPrefs) { prefs.showExit }
val remoteControl = remember(reloadPrefs) { prefs.remoteControl }
val allowAutoMode = remember(reloadPrefs) { prefs.allowAutoMode }
val showExit = remember(reloadPrefs) { prefs.showExit }
val startOnBoot = remember(reloadPrefs) { prefs.startOnBoot }
val isDebugMode = remember(reloadPrefs) { prefs.isDebugMode }

Expand Down Expand Up @@ -330,9 +331,10 @@ fun SettingsScreen(
respectBatterySaver = respectBatterySaver,
respectAutoSyncData = respectAutoSyncData,
keepAlive = keepAlive,
showDetails = showDetails,
showExit = showExit,
remoteControl = remoteControl,
allowAutoMode = allowAutoMode,
showExit = showExit,
startOnBoot = startOnBoot,
isDebugMode = isDebugMode,
onInhibitBatteryOptGrant = {
Expand Down Expand Up @@ -440,6 +442,14 @@ fun SettingsScreen(
prefs.keepAlive = enabled
reloadPrefs++
},
onShowDetailsChange = { enabled ->
prefs.showDetails = enabled
reloadPrefs++
},
onShowExitChange = { enabled ->
prefs.showExit = enabled
reloadPrefs++
},
onRemoteControlChange = { enabled ->
prefs.remoteControl = enabled
reloadPrefs++
Expand All @@ -456,10 +466,6 @@ fun SettingsScreen(

SyncthingService.start(context, action)
},
onShowExitChange = { enabled ->
prefs.showExit = enabled
reloadPrefs++
},
onStartOnBootChange = { enabled ->
prefs.startOnBoot = enabled
reloadPrefs++
Expand Down Expand Up @@ -566,9 +572,10 @@ private fun SettingsContent(
respectBatterySaver: Boolean,
respectAutoSyncData: Boolean,
keepAlive: Boolean,
showDetails: Boolean,
showExit: Boolean,
remoteControl: Boolean,
allowAutoMode: Boolean,
showExit: Boolean,
startOnBoot: Boolean,
isDebugMode: Boolean,
onInhibitBatteryOptGrant: () -> Unit,
Expand All @@ -590,9 +597,10 @@ private fun SettingsContent(
onRespectAutoSyncDataChange: (Boolean) -> Unit,
onSyncScheduleSettingsOpen: () -> Unit,
onKeepAliveChange: (Boolean) -> Unit,
onShowDetailsChange: (Boolean) -> Unit,
onShowExitChange: (Boolean) -> Unit,
onRemoteControlChange: (Boolean) -> Unit,
onAllowAutoModeChange: (Boolean) -> Unit,
onShowExitChange: (Boolean) -> Unit,
onStartOnBootChange: (Boolean) -> Unit,
onDebugModeChange: (Boolean) -> Unit,
onSourceRepoOpen: () -> Unit,
Expand Down Expand Up @@ -844,6 +852,35 @@ private fun SettingsContent(
)
}

item(key = "notifications") {
PreferenceCategory(
title = { Text(text = stringResource(R.string.pref_header_notifications)) },
modifier = Modifier.animateItem(),
)
}

item(key = "show_details") {
SwitchPreference(
checked = showDetails,
onCheckedChange = onShowDetailsChange,
shapes = BetterSegmentedShapes.top(),
title = { Text(text = stringResource(R.string.pref_show_details_name)) },
summary = { Text(text = stringResource(R.string.pref_show_details_desc)) },
modifier = Modifier.animateItem(),
)
}

item(key = "show_exit") {
SwitchPreference(
checked = showExit,
onCheckedChange = onShowExitChange,
shapes = BetterSegmentedShapes.bottom(),
title = { Text(text = stringResource(R.string.pref_show_exit_name)) },
summary = { Text(text = stringResource(R.string.pref_show_exit_desc)) },
modifier = Modifier.animateItem(),
)
}

item(key = "advanced") {
PreferenceCategory(
title = { Text(text = stringResource(R.string.pref_header_advanced)) },
Expand Down Expand Up @@ -873,17 +910,6 @@ private fun SettingsContent(
)
}

item(key = "show_exit") {
SwitchPreference(
checked = showExit,
onCheckedChange = onShowExitChange,
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_show_exit_name)) },
summary = { Text(text = stringResource(R.string.pref_show_exit_desc)) },
modifier = Modifier.animateItem(),
)
}

item(key = "start_on_boot") {
SwitchPreference(
checked = startOnBoot,
Expand Down Expand Up @@ -1016,6 +1042,7 @@ private fun PreviewSettingsScreen() {
manualMode = false,
allowAutoMode = true,
preRunAction = null,
showDetails = true,
showExit = false,
folderStates = SyncthingService.FolderStates(),
deviceStates = SyncthingService.DeviceStates(),
Expand All @@ -1042,9 +1069,10 @@ private fun PreviewSettingsScreen() {
respectBatterySaver = true,
respectAutoSyncData = true,
keepAlive = false,
showDetails = true,
showExit = false,
remoteControl = false,
allowAutoMode = true,
showExit = false,
startOnBoot = true,
isDebugMode = true,
onInhibitBatteryOptGrant = {},
Expand All @@ -1066,9 +1094,10 @@ private fun PreviewSettingsScreen() {
onRespectAutoSyncDataChange = {},
onSyncScheduleSettingsOpen = {},
onKeepAliveChange = {},
onShowDetailsChange = {},
onShowExitChange = {},
onRemoteControlChange = {},
onAllowAutoModeChange = {},
onShowExitChange = {},
onStartOnBootChange = {},
onDebugModeChange = {},
onSourceRepoOpen = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class SyncthingService : Service(), SyncthingStatusReceiver, DeviceStateListener
)
private val STATE_CHANGE_PREFS = arrayOf(
Preferences.PREF_KEEP_ALIVE,
Preferences.PREF_SHOW_DETAILS,
Preferences.PREF_SHOW_EXIT,
)

Expand Down Expand Up @@ -174,10 +175,25 @@ class SyncthingService : Service(), SyncthingStatusReceiver, DeviceStateListener
private val manualMode: Boolean,
private val allowAutoMode: Boolean,
private val preRunAction: PreRunAction?,
val showDetails: Boolean,
private val showExit: Boolean,
val folderStates: FolderStates,
val deviceStates: DeviceStates,
) {
fun equivalent(prev: ServiceState?): Boolean =
prev != null
&& keepAlive == prev.keepAlive
&& blockedReasons == prev.blockedReasons
&& isStarted == prev.isStarted
&& isResumed == prev.isResumed
&& manualMode == prev.manualMode
&& allowAutoMode == prev.allowAutoMode
&& preRunAction == prev.preRunAction
&& showDetails == prev.showDetails
&& showExit == prev.showExit
&& (!showDetails || (folderStates == prev.folderStates
&& deviceStates == prev.deviceStates))

private val shouldResume: Boolean
get() = blockedReasons.isEmpty()

Expand Down Expand Up @@ -654,51 +670,57 @@ class SyncthingService : Service(), SyncthingStatusReceiver, DeviceStateListener
return
}

val notificationState = ServiceState(
val serviceState = ServiceState(
keepAlive = prefs.keepAlive,
blockedReasons = blockedReasons,
isStarted = isStarted,
isResumed = isResumed,
manualMode = prefs.isManualMode,
allowAutoMode = prefs.allowAutoMode,
preRunAction = currentPreRunAction,
showDetails = prefs.showDetails,
showExit = prefs.showExit,
folderStates = syncthingFolderStates,
deviceStates = syncthingDeviceStates,
)

val wasChanged = notificationState != lastServiceState
val wasChanged = serviceState != lastServiceState

if (wasChanged || forceShowNotification) {
if (wasChanged) {
deviceStateTracker.updateBusyFolders(notificationState.folderStates)
deviceStateTracker.updateConnectedDevices(notificationState.deviceStates)
deviceStateTracker.updateBusyFolders(serviceState.folderStates)
deviceStateTracker.updateConnectedDevices(serviceState.deviceStates)

val guiInfo = guiInfo

allListeners { it.onRunStateChanged(notificationState, guiInfo) }
allListeners { it.onRunStateChanged(serviceState, guiInfo) }
}

val (id, notification) = notifications.createPersistentNotification(notificationState)
val useLocation = deviceStateTracker.canUseLocation()
var type = 0
val locationChanged = useLocation != lastUseLocation
val notificationChanged = !serviceState.equivalent(lastServiceState)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
type = type or ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && useLocation) {
type = type or ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
}
if (locationChanged || notificationChanged || forceShowNotification) {
val (id, notification) = notifications.createPersistentNotification(serviceState)
var type = 0

ServiceCompat.startForeground(this, id, notification, type)
notifications.cancelOppositePersistentNotification(id)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
type = type or ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && useLocation) {
type = type or ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
}

ServiceCompat.startForeground(this, id, notification, type)
notifications.cancelOppositePersistentNotification(id)
}

if (lastUseLocation != useLocation) {
if (locationChanged) {
deviceStateTracker.refreshNetworkState()
lastUseLocation = useLocation
}

lastServiceState = notificationState
lastServiceState = serviceState
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
<string name="pref_header_configuration">Configuration</string>
<!-- Section header for preferences to configure when Syncthing is allowed to run. -->
<string name="pref_header_run_conditions">Run conditions</string>
<!-- Section header for preferences related to notifications. -->
<string name="pref_header_notifications">Notifications</string>
<!-- Section header for preferences related to advanced power-user functionality. -->
<string name="pref_header_advanced">Advanced</string>
<!-- Section header for the preference showing information about the app, like version numbers. -->
Expand Down Expand Up @@ -100,6 +102,10 @@
<string name="pref_show_exit_name">Show Exit button</string>
<!-- Description for the preference to show an exit button in the persistent notification. -->
<string name="pref_show_exit_desc">Show an Exit button in the persistent notification. The app will automatically start again after a reboot or when receiving a remote control command.</string>
<!-- Title for the preference to show folder and device states in the persistent notification. -->
<string name="pref_show_details_name">Detailed notifications</string>
<!-- Description for the preference to show folder and device states in the persistent notification. -->
<string name="pref_show_details_desc">Show the status of shared folders and connected devices in the persistent notification.</string>
<!-- Title for the preference to start the app after a reboot. -->
<string name="pref_start_on_boot_name">Start on boot</string>
<!-- Description for the preference to start the app after a reboot. -->
Expand Down