Skip to content

Commit

Permalink
feat: allow settings time intervals for wallpaper changer (closes #215)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bnyro committed Dec 8, 2024
1 parent 73d4ba2 commit 28f16a8
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 6 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ dependencies {

// UI
implementation("androidx.activity:activity-compose:1.8.2")
implementation("androidx.compose.ui:ui:1.6.5")
implementation("androidx.compose.ui:ui:1.7.5")
implementation("androidx.compose.ui:ui-tooling-preview:1.6.5")
implementation("androidx.navigation:navigation-compose:2.7.7")

Expand Down
4 changes: 3 additions & 1 deletion app/src/main/java/com/bnyro/wallpaper/ext/Context.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ import kotlinx.coroutines.withContext
suspend fun Context.toastFromMainThread(text: String?, length: Int = Toast.LENGTH_SHORT)
= withContext(Dispatchers.Main) {
Toast.makeText(this@toastFromMainThread, text, length).show()
}
}

fun Context.toast(text: String?, length: Int = Toast.LENGTH_SHORT) = Toast.makeText(this, text, length).show()
11 changes: 11 additions & 0 deletions app/src/main/java/com/bnyro/wallpaper/ext/FormatTime.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.bnyro.wallpaper.ext

import android.text.format.DateUtils
import androidx.compose.runtime.Composable

@Composable
fun Long.formatTime(): String {
val formatted = DateUtils.formatElapsedTime(this / 1000)

return formatted.substring(0, 5).trimEnd(':')
}
4 changes: 3 additions & 1 deletion app/src/main/java/com/bnyro/wallpaper/obj/WallpaperConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ data class WallpaperConfig(
var source: WallpaperSource = WallpaperSource.ONLINE,
var applyImageFilters: Boolean = true,
var selectedApiRoutes: List<String> = listOf(DrawerScreens.apiScreens[0].route),
var localFolderUris: List<String> = listOf()
var localFolderUris: List<String> = listOf(),
var startTimeMillis: Long? = null,
var endTimeMillis: Long? = null,
) {
fun getSummary(context: Context): String {
val targetString = when (target) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
package com.bnyro.wallpaper.ui.components

import android.text.format.DateUtils
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.material.icons.filled.AccessTimeFilled
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
Expand All @@ -35,6 +42,10 @@ import com.bnyro.wallpaper.obj.WallpaperConfig
import com.bnyro.wallpaper.enums.WallpaperSource
import com.bnyro.wallpaper.enums.WallpaperTarget
import com.bnyro.wallpaper.ext.formatMinutes
import com.bnyro.wallpaper.ext.formatTime
import com.bnyro.wallpaper.ext.toast
import com.bnyro.wallpaper.ext.toastFromMainThread
import com.bnyro.wallpaper.ui.components.dialogs.TimePickerDialog
import com.bnyro.wallpaper.ui.components.prefs.CheckboxPref
import com.bnyro.wallpaper.ui.components.prefs.MultiSelectionBlockPreference
import com.bnyro.wallpaper.ui.components.prefs.ListPreference
Expand Down Expand Up @@ -85,6 +96,12 @@ fun WallpaperChangerPrefDialog(
var applyImageFilters by remember {
mutableStateOf(config.applyImageFilters)
}
var startTimeMillis by remember {
mutableStateOf(config.startTimeMillis)
}
var endTimeMillis by remember {
mutableStateOf(config.endTimeMillis)
}

AlertDialog(
onDismissRequest = onDismissRequest,
Expand All @@ -95,6 +112,12 @@ fun WallpaperChangerPrefDialog(
},
confirmButton = {
DialogButton(stringResource(android.R.string.ok)) {
val hasStartAndEndTime = startTimeMillis != null && endTimeMillis != null
if (hasStartAndEndTime && startTimeMillis!! == endTimeMillis!!) {
context.toast(context.getString(R.string.invalid_time_interval))
return@DialogButton
}

val newConfig = WallpaperConfig(
id = config.id,
changeIntervalMinutes = changeInterval,
Expand All @@ -103,7 +126,9 @@ fun WallpaperChangerPrefDialog(
source = wallpaperSource,
selectedApiRoutes = wallpaperEnginesIndices.map { DrawerScreens.apiScreens[it].route },
localFolderUris = localFolderUris,
applyImageFilters = applyImageFilters
applyImageFilters = applyImageFilters,
startTimeMillis = if (hasStartAndEndTime) startTimeMillis else null,
endTimeMillis = if (hasStartAndEndTime) endTimeMillis else null,
)
onConfigChange(newConfig)
onDismissRequest()
Expand Down Expand Up @@ -233,6 +258,81 @@ fun WallpaperChangerPrefDialog(
) { newValue ->
applyImageFilters = newValue
}

var customTimeInterval by remember {
mutableStateOf(endTimeMillis != null && startTimeMillis != null)
}
CheckboxPref(
prefKey = null,
title = stringResource(R.string.time_interval),
defaultValue = customTimeInterval
) { newValue ->
customTimeInterval = newValue

if (!customTimeInterval) {
startTimeMillis = null
endTimeMillis = null
} else {
startTimeMillis = 0
endTimeMillis = 0
}
}
AnimatedVisibility(visible = customTimeInterval) {
var showStartTimePicker by remember {
mutableStateOf(false)
}

var showEndTimePicker by remember {
mutableStateOf(false)
}

Row(
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Default.AccessTimeFilled,
contentDescription = null
)

Spacer(modifier = Modifier.width(10.dp))

Button(
onClick = { showStartTimePicker = true }
) {
Text((startTimeMillis ?: 0).formatTime())
}

Icon(
modifier = Modifier.padding(horizontal = 10.dp),
imageVector = Icons.AutoMirrored.Default.ArrowForward,
contentDescription = null
)

Button(
onClick = { showEndTimePicker = true }
) {
Text((endTimeMillis ?: 0).formatTime())
}
}

if (showStartTimePicker) {
TimePickerDialog(
startTimeMillis ?: 0,
onTimeChange = { startTimeMillis = it }
) {
showStartTimePicker = false
}
}

if (showEndTimePicker) {
TimePickerDialog(
endTimeMillis ?: 0,
onTimeChange = { endTimeMillis = it }
) {
showEndTimePicker = false
}
}
}
}
}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.bnyro.wallpaper.ui.components.dialogs

import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TimePicker
import androidx.compose.material3.TimePickerLayoutType
import androidx.compose.material3.rememberTimePickerState
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.bnyro.wallpaper.ui.components.DialogButton

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TimePickerDialog(
initialMillis: Long,
onTimeChange: (Long) -> Unit,
onDismissRequest: () -> Unit
) {
val timePickerState = rememberTimePickerState(
initialHour = (initialMillis / 1000 / 60 / 60).toInt(),
initialMinute = (initialMillis / 1000 / 60 % 60).toInt(),
)

AlertDialog(
onDismissRequest = onDismissRequest,
dismissButton = {
DialogButton(stringResource(android.R.string.cancel)) {
onDismissRequest()
}
},
confirmButton = {
DialogButton(stringResource(android.R.string.ok)) {
onTimeChange((timePickerState.hour * 60L + timePickerState.minute) * 60 * 1000)
onDismissRequest()
}
},
text = {
TimePicker(timePickerState, layoutType = TimePickerLayoutType.Vertical)
}
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.bnyro.wallpaper.util

import android.content.Context
import android.graphics.Bitmap
import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.bnyro.wallpaper.db.DatabaseHolder
Expand All @@ -24,7 +23,11 @@ class BackgroundWorker(
it.id == configId
} ?: return Result.success()

Log.e("wallpaper changer", "found appropriate wallpaper config")
val nowMillis = TimeHelper.timeTodayInMillis()
if (config.startTimeMillis != null && config.endTimeMillis != null &&
!TimeHelper.isInTimeRange(nowMillis, config.startTimeMillis!!, config.endTimeMillis!!)
) return Result.success()

return if (runWallpaperChanger(config)) Result.success()
else Result.retry()
}
Expand Down
20 changes: 20 additions & 0 deletions app/src/main/java/com/bnyro/wallpaper/util/TimeHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.bnyro.wallpaper.util

import java.util.Calendar

object TimeHelper {
fun isInTimeRange(currentTimeMillis: Long, startTimeMillis: Long, endTimeMillis: Long): Boolean {
// start and end time are on two different days in this case
if (endTimeMillis < startTimeMillis) {
return currentTimeMillis <= endTimeMillis || currentTimeMillis >= startTimeMillis
}

return currentTimeMillis in startTimeMillis..endTimeMillis
}

fun timeTodayInMillis(): Long {
val calendar = Calendar.getInstance()

return (calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE)) * 60 * 1000L
}
}
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
<string name="invert_wallpaper_by_theme_summary">Invert the wallpaper to be dark on dark themes and light on light themes.</string>
<string name="apply_image_filters">Apply image filters</string>
<string name="add_wallpaper_changer_rule">Add wallpaper changer rule</string>
<string name="time_interval">Time interval</string>
<string name="invalid_time_interval">Invalid time interval</string>
<!-- Network constraints -->
<string name="network_type">Network type</string>
<string name="all_networks">All networks</string>
Expand Down
8 changes: 8 additions & 0 deletions app/src/test/java/com/bnyro/wallpaper/ExampleUnitTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.bnyro.wallpaper

import com.bnyro.wallpaper.util.TimeHelper
import org.junit.Assert.assertEquals
import org.junit.Test

Expand All @@ -13,4 +14,11 @@ class ExampleUnitTest {
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}

@Test
fun testTimeRange() {
assert(TimeHelper.isInTimeRange(500, 200, 700))
assert(!TimeHelper.isInTimeRange(500, 600, 700))
assert(TimeHelper.isInTimeRange(500, 700, 600))
}
}

0 comments on commit 28f16a8

Please sign in to comment.