Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1590e028c |
@@ -65,8 +65,10 @@
|
|||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<!-- MAIN/LAUNCHER lives on the two aliases below, so the launcher
|
<intent-filter>
|
||||||
name can be switched at runtime (#104). -->
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
<!-- Shared text becomes a new task's title. -->
|
<!-- Shared text becomes a new task's title. -->
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
@@ -87,32 +89,6 @@
|
|||||||
<data android:mimeType="text/calendar" />
|
<data android:mimeType="text/calendar" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity-alias
|
|
||||||
android:name=".DefaultNameAlias"
|
|
||||||
android:enabled="true"
|
|
||||||
android:exported="true"
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
|
||||||
android:targetActivity=".MainActivity">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity-alias>
|
|
||||||
<activity-alias
|
|
||||||
android:name=".TasksNameAlias"
|
|
||||||
android:enabled="false"
|
|
||||||
android:exported="true"
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
android:label="@string/app_name_tasks_alias"
|
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
|
||||||
android:targetActivity=".MainActivity">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity-alias>
|
|
||||||
|
|
||||||
<!-- Quick Settings "New task" tile. Only the system QS host can bind it. -->
|
<!-- Quick Settings "New task" tile. Only the system QS host can bind it. -->
|
||||||
<service
|
<service
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import de.jeanlucmakiola.agendula.data.di.LaunchHook
|
|||||||
import de.jeanlucmakiola.agendula.domain.SmartList
|
import de.jeanlucmakiola.agendula.domain.SmartList
|
||||||
import de.jeanlucmakiola.agendula.ui.imports.importIntentUri
|
import de.jeanlucmakiola.agendula.ui.imports.importIntentUri
|
||||||
import de.jeanlucmakiola.agendula.ui.navigation.AppShortcuts
|
import de.jeanlucmakiola.agendula.ui.navigation.AppShortcuts
|
||||||
|
import de.jeanlucmakiola.agendula.data.prefs.ThemeMode
|
||||||
import de.jeanlucmakiola.agendula.ui.RootScreen
|
import de.jeanlucmakiola.agendula.ui.RootScreen
|
||||||
import de.jeanlucmakiola.agendula.ui.crash.CrashReportActivity
|
import de.jeanlucmakiola.agendula.ui.crash.CrashReportActivity
|
||||||
import de.jeanlucmakiola.agendula.ui.navigation.NavRequest
|
import de.jeanlucmakiola.agendula.ui.navigation.NavRequest
|
||||||
@@ -87,15 +88,15 @@ class MainActivity : ComponentActivity() {
|
|||||||
setContent {
|
setContent {
|
||||||
val settingsViewModel: SettingsViewModel = hiltViewModel()
|
val settingsViewModel: SettingsViewModel = hiltViewModel()
|
||||||
val ui by settingsViewModel.state.collectAsStateWithLifecycle()
|
val ui by settingsViewModel.state.collectAsStateWithLifecycle()
|
||||||
val darkTheme = ui.settings.themeMode.isDark(isSystemInDarkTheme())
|
val darkTheme = when (ui.settings.themeMode) {
|
||||||
|
ThemeMode.SYSTEM -> isSystemInDarkTheme()
|
||||||
|
ThemeMode.LIGHT -> false
|
||||||
|
ThemeMode.DARK -> true
|
||||||
|
}
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val use24Hour = ui.settings.timeFormat.is24Hour(DateFormat.is24HourFormat(context))
|
val use24Hour = ui.settings.timeFormat.is24Hour(DateFormat.is24HourFormat(context))
|
||||||
val firstDayOfWeek = ui.settings.weekStart ?: localeFirstDayOfWeek()
|
val firstDayOfWeek = ui.settings.weekStart ?: localeFirstDayOfWeek()
|
||||||
AgendulaTheme(
|
AgendulaTheme(darkTheme = darkTheme, dynamicColor = ui.settings.dynamicColor) {
|
||||||
darkTheme = darkTheme,
|
|
||||||
dynamicColor = ui.settings.dynamicColor,
|
|
||||||
pureBlack = ui.settings.themeMode.isPureBlack,
|
|
||||||
) {
|
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalUse24HourFormat provides use24Hour,
|
LocalUse24HourFormat provides use24Hour,
|
||||||
LocalFirstDayOfWeek provides firstDayOfWeek,
|
LocalFirstDayOfWeek provides firstDayOfWeek,
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
package de.jeanlucmakiola.agendula.data.appname
|
|
||||||
|
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import de.jeanlucmakiola.agendula.ui.navigation.AppShortcuts
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
/** The label the launcher shows for the app (#104). */
|
|
||||||
enum class LauncherName { AGENDULA, TASKS }
|
|
||||||
|
|
||||||
/** The two launcher aliases declared in the manifest. */
|
|
||||||
enum class LauncherAlias { DEFAULT, TASKS }
|
|
||||||
|
|
||||||
/** One component-enable change in an [aliasWritePlan]. */
|
|
||||||
data class AliasStateChange(val alias: LauncherAlias, val enabled: Boolean)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the `TasksNameAlias` enabled state as a [LauncherName]. Only an explicit
|
|
||||||
* enable means "Tasks"; never toggled and disabled both mean the manifest default.
|
|
||||||
*/
|
|
||||||
fun launcherNameFor(tasksAliasState: Int): LauncherName =
|
|
||||||
if (tasksAliasState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
|
|
||||||
LauncherName.TASKS
|
|
||||||
} else {
|
|
||||||
LauncherName.AGENDULA
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The steps to switch to [target]: enable the target alias first, then disable
|
|
||||||
* the other, so the launcher can briefly see two entries but never none.
|
|
||||||
*/
|
|
||||||
fun aliasWritePlan(target: LauncherName): List<AliasStateChange> = when (target) {
|
|
||||||
LauncherName.TASKS -> listOf(
|
|
||||||
AliasStateChange(LauncherAlias.TASKS, enabled = true),
|
|
||||||
AliasStateChange(LauncherAlias.DEFAULT, enabled = false),
|
|
||||||
)
|
|
||||||
LauncherName.AGENDULA -> listOf(
|
|
||||||
AliasStateChange(LauncherAlias.DEFAULT, enabled = true),
|
|
||||||
AliasStateChange(LauncherAlias.TASKS, enabled = false),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Switches the launcher label by enabling one of the two `<activity-alias>`
|
|
||||||
* components. The component state is the only source of truth; nothing is
|
|
||||||
* stored in prefs.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
class LauncherNameManager @Inject constructor(
|
|
||||||
@ApplicationContext private val context: Context,
|
|
||||||
) {
|
|
||||||
private val packageManager: PackageManager get() = context.packageManager
|
|
||||||
|
|
||||||
// The package is the (suffixed) applicationId, the class is namespace-qualified.
|
|
||||||
private fun component(alias: LauncherAlias): ComponentName {
|
|
||||||
val simpleName = when (alias) {
|
|
||||||
LauncherAlias.DEFAULT -> "DefaultNameAlias"
|
|
||||||
LauncherAlias.TASKS -> "TasksNameAlias"
|
|
||||||
}
|
|
||||||
return ComponentName(context.packageName, "$NAMESPACE.$simpleName")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun current(): LauncherName =
|
|
||||||
launcherNameFor(packageManager.getComponentEnabledSetting(component(LauncherAlias.TASKS)))
|
|
||||||
|
|
||||||
fun set(name: LauncherName) {
|
|
||||||
for (change in aliasWritePlan(name)) {
|
|
||||||
val state = if (change.enabled) {
|
|
||||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
|
||||||
} else {
|
|
||||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|
|
||||||
}
|
|
||||||
packageManager.setComponentEnabledSetting(component(change.alias), state, PackageManager.DONT_KILL_APP)
|
|
||||||
}
|
|
||||||
// Dynamic shortcuts hang off the launcher activity, which just changed.
|
|
||||||
AppShortcuts.publish(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
/** `namespace` in app/build.gradle.kts, not the suffixed applicationId. */
|
|
||||||
const val NAMESPACE = "de.jeanlucmakiola.agendula"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,18 +31,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
/** [BLACK] is dark with pure-black surfaces, for AMOLED screens. */
|
enum class ThemeMode { SYSTEM, LIGHT, DARK }
|
||||||
enum class ThemeMode {
|
|
||||||
SYSTEM, LIGHT, DARK, BLACK;
|
|
||||||
|
|
||||||
fun isDark(systemDark: Boolean): Boolean = when (this) {
|
|
||||||
SYSTEM -> systemDark
|
|
||||||
LIGHT -> false
|
|
||||||
DARK, BLACK -> true
|
|
||||||
}
|
|
||||||
|
|
||||||
val isPureBlack: Boolean get() = this == BLACK
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Clock convention: AUTO follows the device's 24-hour switch. */
|
/** Clock convention: AUTO follows the device's 24-hour switch. */
|
||||||
enum class TimeFormatPref { AUTO, TWELVE_HOUR, TWENTY_FOUR_HOUR }
|
enum class TimeFormatPref { AUTO, TWELVE_HOUR, TWENTY_FOUR_HOUR }
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import androidx.core.content.edit
|
|||||||
import de.jeanlucmakiola.agendula.MainActivity
|
import de.jeanlucmakiola.agendula.MainActivity
|
||||||
import de.jeanlucmakiola.agendula.R
|
import de.jeanlucmakiola.agendula.R
|
||||||
import de.jeanlucmakiola.agendula.data.prefs.Settings
|
import de.jeanlucmakiola.agendula.data.prefs.Settings
|
||||||
import de.jeanlucmakiola.agendula.domain.readableDescription
|
|
||||||
import de.jeanlucmakiola.agendula.data.prefs.is24Hour
|
import de.jeanlucmakiola.agendula.data.prefs.is24Hour
|
||||||
import de.jeanlucmakiola.agendula.data.di.ApplicationScope
|
import de.jeanlucmakiola.agendula.data.di.ApplicationScope
|
||||||
import de.jeanlucmakiola.agendula.data.tasks.ProviderResolver
|
import de.jeanlucmakiola.agendula.data.tasks.ProviderResolver
|
||||||
@@ -85,7 +84,6 @@ class TaskNotifier @Inject constructor(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val description = task.description?.readableDescription()?.trim()?.takeIf { it.isNotBlank() }
|
|
||||||
val tapIntent = PendingIntent.getActivity(
|
val tapIntent = PendingIntent.getActivity(
|
||||||
context,
|
context,
|
||||||
task.taskId.toInt(),
|
task.taskId.toInt(),
|
||||||
@@ -95,10 +93,7 @@ class TaskNotifier @Inject constructor(
|
|||||||
val notification = NotificationCompat.Builder(context, channelId)
|
val notification = NotificationCompat.Builder(context, channelId)
|
||||||
.setSmallIcon(R.drawable.ic_notification)
|
.setSmallIcon(R.drawable.ic_notification)
|
||||||
.setContentTitle(title)
|
.setContentTitle(title)
|
||||||
.apply { (text ?: description)?.let(::setContentText) }
|
.apply { if (text != null) setContentText(text) }
|
||||||
.apply {
|
|
||||||
expandedText(text, description)?.let { setStyle(NotificationCompat.BigTextStyle().bigText(it)) }
|
|
||||||
}
|
|
||||||
.setCategory(NotificationCompat.CATEGORY_REMINDER)
|
.setCategory(NotificationCompat.CATEGORY_REMINDER)
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
@@ -245,10 +240,3 @@ private fun relativeDay(date: LocalDate, today: LocalDate, words: RelativeDays,
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The expanded body of a due reminder: the due line, then the task's description. */
|
|
||||||
internal fun expandedText(dueLine: String?, description: String?): String? = when {
|
|
||||||
description == null -> null
|
|
||||||
dueLine == null -> description
|
|
||||||
else -> "$dueLine\n\n$description"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,16 +14,13 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
||||||
import de.jeanlucmakiola.agendula.R
|
import de.jeanlucmakiola.agendula.R
|
||||||
import de.jeanlucmakiola.agendula.data.appname.LauncherName
|
|
||||||
import de.jeanlucmakiola.agendula.data.prefs.ThemeMode
|
import de.jeanlucmakiola.agendula.data.prefs.ThemeMode
|
||||||
import de.jeanlucmakiola.agendula.data.prefs.TimeFormatPref
|
import de.jeanlucmakiola.agendula.data.prefs.TimeFormatPref
|
||||||
import de.jeanlucmakiola.agendula.data.prefs.is24Hour
|
import de.jeanlucmakiola.agendula.data.prefs.is24Hour
|
||||||
import de.jeanlucmakiola.agendula.ui.common.formatMinuteOfDay
|
import de.jeanlucmakiola.agendula.ui.common.formatMinuteOfDay
|
||||||
import de.jeanlucmakiola.agendula.ui.common.localeFirstDayOfWeek
|
import de.jeanlucmakiola.agendula.ui.common.localeFirstDayOfWeek
|
||||||
import de.jeanlucmakiola.floret.components.CollapsingScaffold
|
import de.jeanlucmakiola.floret.components.CollapsingScaffold
|
||||||
import de.jeanlucmakiola.floret.components.GroupedHint
|
|
||||||
import de.jeanlucmakiola.floret.components.GroupedRow
|
import de.jeanlucmakiola.floret.components.GroupedRow
|
||||||
import de.jeanlucmakiola.floret.components.OptionPicker
|
import de.jeanlucmakiola.floret.components.OptionPicker
|
||||||
import de.jeanlucmakiola.floret.components.Position
|
import de.jeanlucmakiola.floret.components.Position
|
||||||
@@ -41,8 +38,6 @@ internal fun AppearanceScreen(
|
|||||||
) {
|
) {
|
||||||
val dynamicColorAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
val dynamicColorAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||||
var showTheme by remember { mutableStateOf(false) }
|
var showTheme by remember { mutableStateOf(false) }
|
||||||
var showAppName by remember { mutableStateOf(false) }
|
|
||||||
val launcherName by viewModel.launcherName.collectAsStateWithLifecycle()
|
|
||||||
var showTimeFormat by remember { mutableStateOf(false) }
|
var showTimeFormat by remember { mutableStateOf(false) }
|
||||||
var showWeekStart by remember { mutableStateOf(false) }
|
var showWeekStart by remember { mutableStateOf(false) }
|
||||||
val systemIs24Hour = DateFormat.is24HourFormat(LocalContext.current)
|
val systemIs24Hour = DateFormat.is24HourFormat(LocalContext.current)
|
||||||
@@ -95,26 +90,6 @@ internal fun AppearanceScreen(
|
|||||||
position = Position.Bottom,
|
position = Position.Bottom,
|
||||||
onClick = { showWeekStart = true },
|
onClick = { showWeekStart = true },
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(Modifier.height(24.dp))
|
|
||||||
GroupedRow(
|
|
||||||
title = stringResource(R.string.settings_app_name),
|
|
||||||
summary = launcherNameLabel(launcherName),
|
|
||||||
position = Position.Alone,
|
|
||||||
onClick = { showAppName = true },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showAppName) {
|
|
||||||
OptionPicker(
|
|
||||||
title = stringResource(R.string.settings_app_name),
|
|
||||||
options = LauncherName.entries,
|
|
||||||
selected = launcherName,
|
|
||||||
label = { launcherNameLabel(it) },
|
|
||||||
header = { GroupedHint(stringResource(R.string.settings_app_name_hint)) },
|
|
||||||
onSelect = viewModel::setLauncherName,
|
|
||||||
onDismiss = { showAppName = false },
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showTimeFormat) {
|
if (showTimeFormat) {
|
||||||
@@ -165,7 +140,6 @@ internal fun AppearanceScreen(
|
|||||||
options = ThemeMode.entries,
|
options = ThemeMode.entries,
|
||||||
selected = state.settings.themeMode,
|
selected = state.settings.themeMode,
|
||||||
label = { stringResource(themeLabel(it)) },
|
label = { stringResource(themeLabel(it)) },
|
||||||
summary = { if (it == ThemeMode.BLACK) stringResource(R.string.settings_theme_black_summary) else null },
|
|
||||||
onSelect = viewModel::setThemeMode,
|
onSelect = viewModel::setThemeMode,
|
||||||
onDismiss = { showTheme = false },
|
onDismiss = { showTheme = false },
|
||||||
)
|
)
|
||||||
@@ -189,17 +163,8 @@ private fun weekStartLabel(day: DayOfWeek?): String =
|
|||||||
/** 14:00, the sample time "Automatic" is shown with. */
|
/** 14:00, the sample time "Automatic" is shown with. */
|
||||||
private const val SAMPLE_MINUTE_OF_DAY = 14 * 60
|
private const val SAMPLE_MINUTE_OF_DAY = 14 * 60
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun launcherNameLabel(name: LauncherName): String = stringResource(
|
|
||||||
when (name) {
|
|
||||||
LauncherName.AGENDULA -> R.string.app_name
|
|
||||||
LauncherName.TASKS -> R.string.app_name_tasks_alias
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun themeLabel(mode: ThemeMode): Int = when (mode) {
|
private fun themeLabel(mode: ThemeMode): Int = when (mode) {
|
||||||
ThemeMode.SYSTEM -> R.string.settings_theme_system
|
ThemeMode.SYSTEM -> R.string.settings_theme_system
|
||||||
ThemeMode.LIGHT -> R.string.settings_theme_light
|
ThemeMode.LIGHT -> R.string.settings_theme_light
|
||||||
ThemeMode.DARK -> R.string.settings_theme_dark
|
ThemeMode.DARK -> R.string.settings_theme_dark
|
||||||
ThemeMode.BLACK -> R.string.settings_theme_black
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package de.jeanlucmakiola.agendula.ui.settings
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import de.jeanlucmakiola.agendula.data.appname.LauncherName
|
|
||||||
import de.jeanlucmakiola.agendula.data.appname.LauncherNameManager
|
|
||||||
import de.jeanlucmakiola.agendula.data.di.IoDispatcher
|
import de.jeanlucmakiola.agendula.data.di.IoDispatcher
|
||||||
import de.jeanlucmakiola.agendula.data.prefs.Settings
|
import de.jeanlucmakiola.agendula.data.prefs.Settings
|
||||||
import de.jeanlucmakiola.agendula.data.prefs.SettingsPrefs
|
import de.jeanlucmakiola.agendula.data.prefs.SettingsPrefs
|
||||||
@@ -35,7 +33,6 @@ import kotlinx.coroutines.flow.flowOn
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.time.DayOfWeek
|
import java.time.DayOfWeek
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -105,8 +102,7 @@ class SettingsViewModel @Inject constructor(
|
|||||||
private val oneShotImport: OneShotImport,
|
private val oneShotImport: OneShotImport,
|
||||||
private val reminderScheduler: ReminderScheduler,
|
private val reminderScheduler: ReminderScheduler,
|
||||||
private val taskNotifier: TaskNotifier,
|
private val taskNotifier: TaskNotifier,
|
||||||
private val launcherNameManager: LauncherNameManager,
|
@IoDispatcher io: CoroutineDispatcher,
|
||||||
@IoDispatcher private val io: CoroutineDispatcher,
|
|
||||||
repository: TasksRepository,
|
repository: TasksRepository,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
@@ -221,23 +217,6 @@ class SettingsViewModel @Inject constructor(
|
|||||||
|
|
||||||
val legacyImportRetrying: StateFlow<Boolean> = retryingLegacyImport
|
val legacyImportRetrying: StateFlow<Boolean> = retryingLegacyImport
|
||||||
|
|
||||||
private val _launcherName = MutableStateFlow(LauncherName.AGENDULA)
|
|
||||||
val launcherName: StateFlow<LauncherName> = _launcherName
|
|
||||||
|
|
||||||
init {
|
|
||||||
viewModelScope.launch { _launcherName.value = withContext(io) { launcherNameManager.current() } }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setLauncherName(name: LauncherName) {
|
|
||||||
_launcherName.value = name
|
|
||||||
viewModelScope.launch {
|
|
||||||
_launcherName.value = withContext(io) {
|
|
||||||
launcherNameManager.set(name)
|
|
||||||
launcherNameManager.current()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setThemeMode(mode: ThemeMode) = viewModelScope.launch { prefs.setThemeMode(mode) }
|
fun setThemeMode(mode: ThemeMode) = viewModelScope.launch { prefs.setThemeMode(mode) }
|
||||||
fun setDynamicColor(enabled: Boolean) = viewModelScope.launch { prefs.setDynamicColor(enabled) }
|
fun setDynamicColor(enabled: Boolean) = viewModelScope.launch { prefs.setDynamicColor(enabled) }
|
||||||
fun setDefaultList(id: Long?) = viewModelScope.launch { prefs.setDefaultListId(id) }
|
fun setDefaultList(id: Long?) = viewModelScope.launch { prefs.setDefaultListId(id) }
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import de.jeanlucmakiola.floret.identity.FloretExpressiveTheme
|
|||||||
fun AgendulaTheme(
|
fun AgendulaTheme(
|
||||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
dynamicColor: Boolean = true,
|
dynamicColor: Boolean = true,
|
||||||
pureBlack: Boolean = false,
|
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
FloretExpressiveTheme(
|
FloretExpressiveTheme(
|
||||||
@@ -23,7 +22,6 @@ fun AgendulaTheme(
|
|||||||
darkScheme = AgendulaDarkFallback,
|
darkScheme = AgendulaDarkFallback,
|
||||||
darkTheme = darkTheme,
|
darkTheme = darkTheme,
|
||||||
dynamicColor = dynamicColor,
|
dynamicColor = dynamicColor,
|
||||||
pureBlack = pureBlack,
|
|
||||||
typography = AgendulaTypography,
|
typography = AgendulaTypography,
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import de.jeanlucmakiola.agendula.R
|
import de.jeanlucmakiola.agendula.R
|
||||||
import de.jeanlucmakiola.agendula.data.prefs.Settings
|
import de.jeanlucmakiola.agendula.data.prefs.Settings
|
||||||
import de.jeanlucmakiola.agendula.data.prefs.SettingsPrefs
|
import de.jeanlucmakiola.agendula.data.prefs.SettingsPrefs
|
||||||
|
import de.jeanlucmakiola.agendula.data.prefs.ThemeMode
|
||||||
import de.jeanlucmakiola.agendula.data.tasks.TasksRepository
|
import de.jeanlucmakiola.agendula.data.tasks.TasksRepository
|
||||||
import de.jeanlucmakiola.agendula.domain.SavedFilter
|
import de.jeanlucmakiola.agendula.domain.SavedFilter
|
||||||
import de.jeanlucmakiola.agendula.domain.SmartList
|
import de.jeanlucmakiola.agendula.domain.SmartList
|
||||||
@@ -134,12 +135,12 @@ class TaskWidgetConfigActivity : ComponentActivity() {
|
|||||||
rowColor = parseWidgetRowColor(state[WIDGET_ROW_COLOR_KEY])
|
rowColor = parseWidgetRowColor(state[WIDGET_ROW_COLOR_KEY])
|
||||||
selectedListIds = parseWidgetListIds(state[WIDGET_LIST_IDS_KEY])
|
selectedListIds = parseWidgetListIds(state[WIDGET_LIST_IDS_KEY])
|
||||||
}
|
}
|
||||||
val dark = settings.themeMode.isDark(isSystemInDarkTheme())
|
val dark = when (settings.themeMode) {
|
||||||
AgendulaTheme(
|
ThemeMode.SYSTEM -> isSystemInDarkTheme()
|
||||||
darkTheme = dark,
|
ThemeMode.LIGHT -> false
|
||||||
dynamicColor = settings.dynamicColor,
|
ThemeMode.DARK -> true
|
||||||
pureBlack = settings.themeMode.isPureBlack,
|
}
|
||||||
) {
|
AgendulaTheme(darkTheme = dark, dynamicColor = settings.dynamicColor) {
|
||||||
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.surface) {}
|
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.surface) {}
|
||||||
WidgetFilterPicker(
|
WidgetFilterPicker(
|
||||||
kind = kind,
|
kind = kind,
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ internal fun effectiveThemeMode(appThemeMode: ThemeMode, override: WidgetThemeMo
|
|||||||
override ?: when (appThemeMode) {
|
override ?: when (appThemeMode) {
|
||||||
ThemeMode.SYSTEM -> WidgetThemeMode.SYSTEM
|
ThemeMode.SYSTEM -> WidgetThemeMode.SYSTEM
|
||||||
ThemeMode.LIGHT -> WidgetThemeMode.LIGHT
|
ThemeMode.LIGHT -> WidgetThemeMode.LIGHT
|
||||||
ThemeMode.DARK, ThemeMode.BLACK -> WidgetThemeMode.DARK
|
ThemeMode.DARK -> WidgetThemeMode.DARK
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The smart lists a widget can show, in picker order. */
|
/** The smart lists a widget can show, in picker order. */
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Agendula</string>
|
<string name="app_name">Agendula</string>
|
||||||
<string name="app_name_tasks_alias">Tasks</string>
|
|
||||||
|
|
||||||
<!-- Generic -->
|
<!-- Generic -->
|
||||||
<string name="task_untitled">Untitled task</string>
|
<string name="task_untitled">Untitled task</string>
|
||||||
@@ -449,10 +448,6 @@
|
|||||||
<string name="settings_theme_system">Follow system</string>
|
<string name="settings_theme_system">Follow system</string>
|
||||||
<string name="settings_theme_light">Light</string>
|
<string name="settings_theme_light">Light</string>
|
||||||
<string name="settings_theme_dark">Dark</string>
|
<string name="settings_theme_dark">Dark</string>
|
||||||
<string name="settings_theme_black">Black</string>
|
|
||||||
<string name="settings_theme_black_summary">Dark with pure black backgrounds, for AMOLED screens</string>
|
|
||||||
<string name="settings_app_name">App name</string>
|
|
||||||
<string name="settings_app_name_hint">Show Agendula as “Tasks” in your launcher. Only the launcher name changes; the icon may move to a new spot. Agendula closes when you switch, so reopen it from the launcher.</string>
|
|
||||||
<string name="settings_dynamic_color">Dynamic colour</string>
|
<string name="settings_dynamic_color">Dynamic colour</string>
|
||||||
<string name="settings_dynamic_color_hint">Use colours from your wallpaper</string>
|
<string name="settings_dynamic_color_hint">Use colours from your wallpaper</string>
|
||||||
<string name="settings_section_reminders">Notifications</string>
|
<string name="settings_section_reminders">Notifications</string>
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
package de.jeanlucmakiola.agendula.data.appname
|
|
||||||
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
|
|
||||||
class LauncherNameManagerTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `an enabled Tasks alias reads as Tasks`() {
|
|
||||||
assertThat(launcherNameFor(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)).isEqualTo(LauncherName.TASKS)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `a default or disabled Tasks alias reads as Agendula`() {
|
|
||||||
assertThat(launcherNameFor(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)).isEqualTo(LauncherName.AGENDULA)
|
|
||||||
assertThat(launcherNameFor(PackageManager.COMPONENT_ENABLED_STATE_DISABLED)).isEqualTo(LauncherName.AGENDULA)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `switching always enables the target before disabling the other`() {
|
|
||||||
assertThat(aliasWritePlan(LauncherName.TASKS)).containsExactly(
|
|
||||||
AliasStateChange(LauncherAlias.TASKS, enabled = true),
|
|
||||||
AliasStateChange(LauncherAlias.DEFAULT, enabled = false),
|
|
||||||
).inOrder()
|
|
||||||
assertThat(aliasWritePlan(LauncherName.AGENDULA)).containsExactly(
|
|
||||||
AliasStateChange(LauncherAlias.DEFAULT, enabled = true),
|
|
||||||
AliasStateChange(LauncherAlias.TASKS, enabled = false),
|
|
||||||
).inOrder()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package de.jeanlucmakiola.agendula.data.reminders
|
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
|
|
||||||
class ExpandedTextTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `no description means no expanded body`() {
|
|
||||||
assertThat(expandedText("Due today", null)).isNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `description alone when there is no due line`() {
|
|
||||||
assertThat(expandedText(null, "Buy oat milk")).isEqualTo("Buy oat milk")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `due line comes first, separated by a blank line`() {
|
|
||||||
assertThat(expandedText("Due today", "Buy oat milk")).isEqualTo("Due today\n\nBuy oat milk")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -210,7 +210,6 @@ class WidgetDataTest {
|
|||||||
fun `no override resolves to whatever the app's own theme means`() {
|
fun `no override resolves to whatever the app's own theme means`() {
|
||||||
assertThat(readyWithTheme(ThemeMode.DARK).effectiveThemeMode(null)).isEqualTo(WidgetThemeMode.DARK)
|
assertThat(readyWithTheme(ThemeMode.DARK).effectiveThemeMode(null)).isEqualTo(WidgetThemeMode.DARK)
|
||||||
assertThat(readyWithTheme(ThemeMode.SYSTEM).effectiveThemeMode(null)).isEqualTo(WidgetThemeMode.SYSTEM)
|
assertThat(readyWithTheme(ThemeMode.SYSTEM).effectiveThemeMode(null)).isEqualTo(WidgetThemeMode.SYSTEM)
|
||||||
assertThat(readyWithTheme(ThemeMode.BLACK).effectiveThemeMode(null)).isEqualTo(WidgetThemeMode.DARK)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ xpp3 = "1.1.6"
|
|||||||
# Parses the raw SRV/TXT answers for RFC 6764 discovery; the lookup itself goes
|
# Parses the raw SRV/TXT answers for RFC 6764 discovery; the lookup itself goes
|
||||||
# through Android's DnsResolver, so it follows the network and Private DNS.
|
# through Android's DnsResolver, so it follows the network and Private DNS.
|
||||||
# BSD-3 — it goes on the attribution screen with the rest.
|
# BSD-3 — it goes on the attribution screen with the rest.
|
||||||
dnsjava = "3.6.3"
|
dnsjava = "3.6.5"
|
||||||
# WebDAV-Push delivery. The connector only: DAVx5 also ships the embedded FCM
|
# WebDAV-Push delivery. The connector only: DAVx5 also ships the embedded FCM
|
||||||
# distributor, which pulls in Play Services and would get us flagged on F-Droid.
|
# distributor, which pulls in Play Services and would get us flagged on F-Droid.
|
||||||
unifiedpush = "3.3.5"
|
unifiedpush = "3.3.5"
|
||||||
|
|||||||
Reference in New Issue
Block a user