Skip to content
Merged
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
5 changes: 5 additions & 0 deletions app/src/main/java/com/chiller3/basicsync/Preferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Preferences(context: Context) {
const val PREF_RESPECT_AUTO_SYNC_DATA = "respect_auto_sync_data"
const val PREF_KEEP_ALIVE = "keep_alive"
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_REQUIRE_UNMETERED_NETWORK = "require_unmetered_network"
const val PREF_NETWORK_ALLOW_WIFI = "network_allow_wifi"
Expand Down Expand Up @@ -76,6 +77,10 @@ class Preferences(context: Context) {
get() = prefs.getBoolean(PREF_REMOTE_CONTROL, false)
set(enabled) = prefs.edit { putBoolean(PREF_REMOTE_CONTROL, enabled) }

var allowAutoMode: Boolean
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) }
Expand Down
142 changes: 87 additions & 55 deletions app/src/main/java/com/chiller3/basicsync/settings/SettingsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ fun SettingsScreen(
val respectAutoSyncData = remember(reloadPrefs) { prefs.respectAutoSyncData }
val keepAlive = remember(reloadPrefs) { prefs.keepAlive }
val remoteControl = remember(reloadPrefs) { prefs.remoteControl }
val allowAutoMode = remember(reloadPrefs) { prefs.allowAutoMode }
val showExit = remember(reloadPrefs) { prefs.showExit }
val isDebugMode = remember(reloadPrefs) { prefs.isDebugMode }

Expand Down Expand Up @@ -295,6 +296,7 @@ fun SettingsScreen(
respectAutoSyncData = respectAutoSyncData,
keepAlive = keepAlive,
remoteControl = remoteControl,
allowAutoMode = allowAutoMode,
showExit = showExit,
isDebugMode = isDebugMode,
onInhibitBatteryOptGrant = {
Expand Down Expand Up @@ -386,6 +388,18 @@ fun SettingsScreen(
prefs.remoteControl = enabled
reloadPrefs++
},
onAllowAutoModeChange = { enabled ->
prefs.allowAutoMode = enabled
reloadPrefs++

val action = if (enabled) {
SyncthingService.ACTION_RENOTIFY
} else {
SyncthingService.ACTION_MANUAL_MODE
}

SyncthingService.start(context, action)
},
onShowExitChange = { enabled ->
prefs.showExit = enabled
reloadPrefs++
Expand Down Expand Up @@ -491,6 +505,7 @@ private fun SettingsContent(
respectAutoSyncData: Boolean,
keepAlive: Boolean,
remoteControl: Boolean,
allowAutoMode: Boolean,
showExit: Boolean,
isDebugMode: Boolean,
onInhibitBatteryOptGrant: () -> Unit,
Expand All @@ -511,6 +526,7 @@ private fun SettingsContent(
onSyncScheduleSettingsOpen: () -> Unit,
onKeepAliveChange: (Boolean) -> Unit,
onRemoteControlChange: (Boolean) -> Unit,
onAllowAutoModeChange: (Boolean) -> Unit,
onShowExitChange: (Boolean) -> Unit,
onDebugModeChange: (Boolean) -> Unit,
onSourceRepoOpen: () -> Unit,
Expand Down Expand Up @@ -665,73 +681,75 @@ private fun SettingsContent(
)
}

item(key = "auto_mode") {
SwitchPreference(
checked = !isManualMode,
onCheckedChange = { onManualModeChange(!it) },
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_auto_mode_name)) },
summary = { Text(text = stringResource(R.string.pref_auto_mode_desc)) },
modifier = Modifier.animateItem(),
)
}

item(key = "network_conditions") {
Preference(
onClick = onNetworkConditionsOpen,
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_network_conditions_name)) },
summary = { Text(text = stringResource(R.string.pref_network_conditions_desc)) },
modifier = Modifier.animateItem(),
)
}

if (hasBattery) {
item(key = "run_on_battery") {
val summary = stringResource(R.string.pref_run_on_battery_desc, minBatteryLevel)
if (allowAutoMode) {
item(key = "auto_mode") {
SwitchPreference(
checked = !isManualMode,
onCheckedChange = { onManualModeChange(!it) },
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_auto_mode_name)) },
summary = { Text(text = stringResource(R.string.pref_auto_mode_desc)) },
modifier = Modifier.animateItem(),
)
}

SplitSwitchPreference(
onClick = { showMinBatteryLevelDialog = true },
checked = runOnBattery,
onCheckedChange = onRunOnBatteryChange,
item(key = "network_conditions") {
Preference(
onClick = onNetworkConditionsOpen,
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_run_on_battery_name)) },
summary = { Text(text = summary) },
title = { Text(text = stringResource(R.string.pref_network_conditions_name)) },
summary = { Text(text = stringResource(R.string.pref_network_conditions_desc)) },
modifier = Modifier.animateItem(),
)
}

item(key = "respect_battery_saver") {
if (hasBattery) {
item(key = "run_on_battery") {
val summary = stringResource(R.string.pref_run_on_battery_desc, minBatteryLevel)

SplitSwitchPreference(
onClick = { showMinBatteryLevelDialog = true },
checked = runOnBattery,
onCheckedChange = onRunOnBatteryChange,
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_run_on_battery_name)) },
summary = { Text(text = summary) },
modifier = Modifier.animateItem(),
)
}

item(key = "respect_battery_saver") {
SwitchPreference(
checked = respectBatterySaver,
onCheckedChange = onRespectBatterySaverChange,
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_respect_battery_saver_name)) },
summary = { Text(text = stringResource(R.string.pref_respect_battery_saver_desc)) },
modifier = Modifier.animateItem(),
)
}
}

item(key = "respect_auto_sync_data") {
SwitchPreference(
checked = respectBatterySaver,
onCheckedChange = onRespectBatterySaverChange,
checked = respectAutoSyncData,
onCheckedChange = onRespectAutoSyncDataChange,
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_respect_battery_saver_name)) },
summary = { Text(text = stringResource(R.string.pref_respect_battery_saver_desc)) },
title = { Text(text = stringResource(R.string.pref_respect_auto_sync_data_name)) },
summary = { Text(text = stringResource(R.string.pref_respect_auto_sync_data_desc)) },
modifier = Modifier.animateItem(),
)
}
}

item(key = "respect_auto_sync_data") {
SwitchPreference(
checked = respectAutoSyncData,
onCheckedChange = onRespectAutoSyncDataChange,
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_respect_auto_sync_data_name)) },
summary = { Text(text = stringResource(R.string.pref_respect_auto_sync_data_desc)) },
modifier = Modifier.animateItem(),
)
}

item(key = "sync_schedule_settings") {
Preference(
onClick = onSyncScheduleSettingsOpen,
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_sync_schedule_settings_name)) },
summary = { Text(text = stringResource(R.string.pref_sync_schedule_settings_desc)) },
modifier = Modifier.animateItem(),
)
item(key = "sync_schedule_settings") {
Preference(
onClick = onSyncScheduleSettingsOpen,
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_sync_schedule_settings_name)) },
summary = { Text(text = stringResource(R.string.pref_sync_schedule_settings_desc)) },
modifier = Modifier.animateItem(),
)
}
}

item(key = "keep_alive") {
Expand Down Expand Up @@ -763,6 +781,17 @@ private fun SettingsContent(
)
}

item(key = "allow_auto_mode") {
SwitchPreference(
checked = allowAutoMode,
onCheckedChange = onAllowAutoModeChange,
shapes = BetterSegmentedShapes.middle(),
title = { Text(text = stringResource(R.string.pref_allow_auto_mode_name)) },
summary = { Text(text = stringResource(R.string.pref_allow_auto_mode_desc)) },
modifier = Modifier.animateItem(),
)
}

item(key = "show_exit") {
SwitchPreference(
checked = showExit,
Expand Down Expand Up @@ -895,6 +924,7 @@ private fun PreviewSettingsScreen() {
isStarted = true,
isResumed = true,
manualMode = false,
allowAutoMode = true,
preRunAction = null,
showExit = false,
)
Expand All @@ -919,6 +949,7 @@ private fun PreviewSettingsScreen() {
respectAutoSyncData = true,
keepAlive = false,
remoteControl = false,
allowAutoMode = true,
showExit = false,
isDebugMode = true,
onInhibitBatteryOptGrant = {},
Expand All @@ -939,6 +970,7 @@ private fun PreviewSettingsScreen() {
onSyncScheduleSettingsOpen = {},
onKeepAliveChange = {},
onRemoteControlChange = {},
onAllowAutoModeChange = {},
onShowExitChange = {},
onDebugModeChange = {},
onSourceRepoOpen = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class SyncthingService : Service(), SyncthingStatusReceiver, DeviceStateListener
private val isStarted: Boolean,
private val isResumed: Boolean,
private val manualMode: Boolean,
private val allowAutoMode: Boolean,
private val preRunAction: PreRunAction?,
private val showExit: Boolean,
) {
Expand Down Expand Up @@ -128,7 +129,9 @@ class SyncthingService : Service(), SyncthingStatusReceiver, DeviceStateListener
get() = ArrayList<String>().apply {
if (preRunAction == null) {
if (manualMode) {
add(ACTION_AUTO_MODE)
if (allowAutoMode) {
add(ACTION_AUTO_MODE)
}

if (shouldResume) {
add(ACTION_STOP)
Expand Down Expand Up @@ -317,7 +320,13 @@ class SyncthingService : Service(), SyncthingStatusReceiver, DeviceStateListener
var forceShowNotification = false

when (intent?.action) {
ACTION_AUTO_MODE -> prefs.isManualMode = false
ACTION_AUTO_MODE -> {
if (prefs.allowAutoMode) {
prefs.isManualMode = false
} else {
Log.d(TAG, "Ignoring switch to auto mode because auto mode is blocked")
}
}
ACTION_MANUAL_MODE -> {
// Keep the current state since the user has no way to know what the previously
// saved state is anyway.
Expand Down Expand Up @@ -431,6 +440,7 @@ class SyncthingService : Service(), SyncthingStatusReceiver, DeviceStateListener
isStarted = isStarted,
isResumed = isResumed,
manualMode = prefs.isManualMode,
allowAutoMode = prefs.allowAutoMode,
preRunAction = currentPreRunAction,
showExit = prefs.showExit,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ class SyncthingTileService : TileService(), SharedPreferences.OnSharedPreference
} else if (prefs.manualShouldRun) {
// Manually started -> manually stopped.
SyncthingService.ACTION_STOP
} else {
// Manually stopped -> auto mode.
} else if (prefs.allowAutoMode) {
// Manually stopped -> auto mode (when auto mode allowed).
SyncthingService.ACTION_AUTO_MODE
} else {
// Manually stopped -> manually started (when auto mode blocked).
SyncthingService.ACTION_START
}

startForegroundService(SyncthingService.createIntent(this, action))
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@
<string name="pref_remote_control_name">Allow remote control</string>
<!-- Description for the preference that allows external apps to control when Syncthing runs. -->
<string name="pref_remote_control_desc">Allow external apps to switch to auto mode or manually start and stop Syncthing.</string>
<!-- Title for the preference for controlling whether auto mode can be used. -->
<string name="pref_allow_auto_mode_name">Allow auto mode</string>
<!-- Description for the preference for controlling whether auto mode can be used. -->
<string name="pref_allow_auto_mode_desc">When disabled, all auto mode functionality is completely removed from the app, notification, and quick settings tile.</string>
<!-- Title for the preference to show an exit button in the persistent notification. -->
<string name="pref_show_exit_name">Show Exit button</string>
<!-- Description for the preference to show an exit button in the persistent notification. -->
Expand Down