diff --git a/app-base/src/main/res/values/strings.xml b/app-base/src/main/res/values/strings.xml
index 014fa5d6..6be2fd67 100644
--- a/app-base/src/main/res/values/strings.xml
+++ b/app-base/src/main/res/values/strings.xml
@@ -162,6 +162,7 @@
Screen
Wake up the phone and show a reminding screen
+ Pick Step Image
Always Fullscreen
Halt
diff --git a/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/BehaviourSettingsView.kt b/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/BehaviourSettingsView.kt
index 65006b9b..66eac550 100644
--- a/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/BehaviourSettingsView.kt
+++ b/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/BehaviourSettingsView.kt
@@ -99,9 +99,16 @@ internal fun MaterialPopupMenuBuilder.addVibrationItems(
internal fun MaterialPopupMenuBuilder.addScreenItems(
context: Context,
action: ScreenAction,
+ onPickImageClick: () -> Unit,
onFullscreenChanged: (Boolean) -> Unit
) {
section {
+ item {
+ label = context.getString(RBase.string.screen_pick_image)
+ callback = {
+ onPickImageClick.invoke()
+ }
+ }
switchItem {
label = context.getString(RBase.string.screen_fullscreen)
onBind = {
diff --git a/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/EditActivity.kt b/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/EditActivity.kt
index dfae6215..b515f3a2 100644
--- a/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/EditActivity.kt
+++ b/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/EditActivity.kt
@@ -2,6 +2,7 @@ package xyz.aprildown.timer.app.timer.edit
import android.app.Activity
import android.content.ClipboardManager
+import android.content.Intent
import android.graphics.Typeface
import android.net.Uri
import android.os.Bundle
@@ -12,6 +13,7 @@ import android.view.View
import androidx.activity.addCallback
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
+import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.annotation.VisibleForTesting
@@ -24,6 +26,7 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.core.widget.doAfterTextChanged
+import androidx.documentfile.provider.DocumentFile
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@@ -68,6 +71,7 @@ import xyz.aprildown.timer.domain.usecases.Fruit
import xyz.aprildown.timer.domain.utils.Constants
import xyz.aprildown.timer.presentation.edit.EditViewModel
import xyz.aprildown.timer.presentation.stream.accumulateTime
+import xyz.aprildown.ultimateringtonepicker.getParcelableArrayExtraCompat
import javax.inject.Inject
import xyz.aprildown.timer.app.base.R as RBase
@@ -95,6 +99,30 @@ class EditActivity :
getRingtonePickerResultCallback()
)
+ private var imagePickerLauncherPosition = -1
+ private val imagePickerLauncher = registerForActivityResult(
+ ActivityResultContracts.PickVisualMedia()
+ ) { uri ->
+ var title = ""
+ if (uri != null) {
+ val file = DocumentFile.fromSingleUri(
+ this@EditActivity,
+ uri
+ )
+ title = file?.name ?: ""
+ }
+
+ changeBehaviour(BehaviourType.SCREEN, imagePickerLauncherPosition) {
+ it
+ .toScreenAction()
+ .copy(
+ title = title,
+ uri = uri?.toString() ?: ""
+ )
+ .toBehaviourEntity()
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityEditTimerBinding.inflate(layoutInflater)
@@ -674,6 +702,16 @@ class EditActivity :
addScreenItems(
context = this@EditActivity,
action = current.toScreenAction(),
+ onPickImageClick = {
+ imagePickerLauncherPosition = position
+
+ imagePickerLauncher
+ .launch(
+ PickVisualMediaRequest(
+ ActivityResultContracts.PickVisualMedia.ImageOnly
+ )
+ )
+ },
onFullscreenChanged = { isChecked ->
changeBehaviour(BehaviourType.SCREEN, position) {
it.toScreenAction().copy(fullScreen = isChecked).toBehaviourEntity()
diff --git a/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/UpdateStepDialog.kt b/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/UpdateStepDialog.kt
index 9a642008..f53a596c 100644
--- a/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/UpdateStepDialog.kt
+++ b/app-timer-edit/src/main/java/xyz/aprildown/timer/app/timer/edit/UpdateStepDialog.kt
@@ -5,9 +5,12 @@ import android.net.Uri
import android.os.Bundle
import android.view.View
import android.widget.EditText
+import androidx.activity.result.PickVisualMediaRequest
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.cardview.widget.CardView
import androidx.core.net.toUri
import androidx.core.widget.ImageViewCompat
+import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.DialogFragment
import com.github.deweyreed.tools.helper.gone
import com.github.deweyreed.tools.helper.toColorStateList
@@ -179,6 +182,35 @@ class UpdateStepDialog :
addScreenItems(
context = context,
action = current.toScreenAction(),
+ onPickImageClick = {
+ registerForActivityResult(
+ ActivityResultContracts.PickVisualMedia()
+ ) { uri ->
+ var title = ""
+ if (uri != null) {
+ val file = DocumentFile.fromSingleUri(
+ context,
+ uri
+ )
+ title = file?.name ?: ""
+ }
+
+ changeBehaviour(BehaviourType.SCREEN) {
+ it
+ .toScreenAction()
+ .copy(
+ title = title,
+ uri = uri.toString()
+ )
+ .toBehaviourEntity()
+ }
+ }
+ .launch(
+ PickVisualMediaRequest(
+ ActivityResultContracts.PickVisualMedia.ImageOnly
+ )
+ )
+ },
onFullscreenChanged = { isChecked ->
changeBehaviour(BehaviourType.SCREEN) {
it.toScreenAction().copy(fullScreen = isChecked).toBehaviourEntity()
diff --git a/app-timer-run/build.gradle b/app-timer-run/build.gradle
index bb9ebf58..a5f93743 100644
--- a/app-timer-run/build.gradle
+++ b/app-timer-run/build.gradle
@@ -19,4 +19,6 @@ dependencies {
implementation libs.hilt.android
kapt libs.hilt.compiler
+ implementation libs.glide
+ annotationProcessor libs.compiler
}
diff --git a/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/MachineService.kt b/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/MachineService.kt
index 9ca83c81..730bf54e 100644
--- a/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/MachineService.kt
+++ b/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/MachineService.kt
@@ -353,20 +353,21 @@ class MachineService :
VibrateHelper.stop(this)
}
- override fun showScreen(timerItem: TimerEntity, currentStepName: String, fullScreen: Boolean) {
+ override fun showScreen(timerItem: TimerEntity, currentStepName: String, fullScreen: Boolean, imagePath: String) {
if (fullScreen) {
startActivity(
ScreenActivity.intent(
this,
timerItem.id,
timerItem.name,
- currentStepName
+ currentStepName,
+ imagePath
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
} else {
notificationManager.notify(
Constants.NOTIF_ID_SCREEN,
- buildScreenNotificationBuilder(timerItem, currentStepName).build()
+ buildScreenNotificationBuilder(timerItem, currentStepName, imagePath).build()
)
}
}
diff --git a/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/NotificationBuilders.kt b/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/NotificationBuilders.kt
index 4cc02609..d64024e4 100644
--- a/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/NotificationBuilders.kt
+++ b/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/NotificationBuilders.kt
@@ -257,7 +257,8 @@ private fun Builder.withMediaStyleNotification(context: Context): Builder {
*/
internal fun Context.buildScreenNotificationBuilder(
timerItem: TimerEntity,
- currentStepName: String
+ currentStepName: String,
+ imagePath: String,
): Builder {
val res = resources
val actions = arrayListOf()
@@ -280,7 +281,7 @@ internal fun Context.buildScreenNotificationBuilder(
)
val showScreenIntent =
- ScreenActivity.intent(this, timerId, timerItem.name, currentStepName)
+ ScreenActivity.intent(this, timerId, timerItem.name, currentStepName, imagePath)
val pendingShowScreenIntent = pendingActivityIntent(showScreenIntent, timerId)
// Full screen intent has flags so it is different than the content intent.
diff --git a/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/screen/ScreenActivity.kt b/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/screen/ScreenActivity.kt
index c77a4383..8b17ee06 100644
--- a/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/screen/ScreenActivity.kt
+++ b/app-timer-run/src/main/java/xyz/aprildown/timer/app/timer/run/screen/ScreenActivity.kt
@@ -6,6 +6,7 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
+import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.IBinder
@@ -18,6 +19,7 @@ import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
+import com.bumptech.glide.Glide
import com.github.deweyreed.tools.arch.observeEvent
import com.github.deweyreed.tools.helper.startDrawableAnimation
import com.github.deweyreed.tools.helper.stopDrawableAnimation
@@ -30,6 +32,7 @@ import xyz.aprildown.timer.domain.entities.TimerEntity
import xyz.aprildown.timer.domain.utils.Constants
import xyz.aprildown.timer.presentation.screen.ScreenViewModel
import xyz.aprildown.timer.presentation.stream.MachineContract
+import java.io.File
import com.github.deweyreed.tools.R as RTools
@AndroidEntryPoint
@@ -70,6 +73,17 @@ class ScreenActivity : BaseActivity() {
}
}
+ intent?.getStringExtra(EXTRA_IMAGE_PATH)?.let { imagePath ->
+ if (imagePath.isNotEmpty()) {
+ val image = File(imagePath)
+ if (image.extension == "gif")
+ Glide.with(this).asGif().load(Uri.parse(imagePath)).into(binding.image)
+ else
+ Glide.with(this).asBitmap().load(Uri.parse(imagePath)).into(binding.image)
+// binding.image.setImageURI(Uri.parse(imagePath))
+ }
+ }
+
viewModel.setTimerId(
intent?.getIntExtra(Constants.EXTRA_TIMER_ID, TimerEntity.NULL_ID)
?: TimerEntity.NULL_ID
@@ -162,13 +176,9 @@ class ScreenActivity : BaseActivity() {
override fun onResume() {
super.onResume()
- binding.imageRingtone.post {
- binding.imageRingtone.startDrawableAnimation()
- }
}
override fun onPause() {
- binding.imageRingtone.stopDrawableAnimation()
super.onPause()
}
@@ -190,15 +200,17 @@ class ScreenActivity : BaseActivity() {
companion object {
private const val EXTRA_NAME = "extra_name"
private const val EXTRA_STEP_NAME = "extra_step_name"
+ private const val EXTRA_IMAGE_PATH = "extra_image_path"
@SuppressLint("StaticFieldLeak")
var screen: Activity? = null
- fun intent(context: Context, id: Int, timerName: String, stepName: String): Intent {
+ fun intent(context: Context, id: Int, timerName: String, stepName: String, imagePath: String): Intent {
return Intent(context, ScreenActivity::class.java)
.putExtra(Constants.EXTRA_TIMER_ID, id)
.putExtra(EXTRA_NAME, timerName)
.putExtra(EXTRA_STEP_NAME, stepName)
+ .putExtra(EXTRA_IMAGE_PATH, imagePath)
}
}
}
diff --git a/app-timer-run/src/main/res/layout-land/activity_screen.xml b/app-timer-run/src/main/res/layout-land/activity_screen.xml
index d714d8eb..1f7ac23e 100644
--- a/app-timer-run/src/main/res/layout-land/activity_screen.xml
+++ b/app-timer-run/src/main/res/layout-land/activity_screen.xml
@@ -9,44 +9,35 @@
+ android:scaleType="center"
+ app:layout_constraintEnd_toStartOf="@+id/btnStop"
+ app:layout_constraintStart_toEndOf="@+id/textStepInfo"
+ tools:layout_editor_absoluteY="21dp" />
+ app:rippleColor="?colorOnPrimarySurface"
+ tools:layout_editor_absoluteX="16dp"
+ tools:layout_editor_absoluteY="16dp" />
+ app:srcCompat="@drawable/ic_stop"
+ tools:layout_editor_absoluteX="625dp"
+ tools:layout_editor_absoluteY="165dp" />
diff --git a/app-timer-run/src/main/res/layout/activity_screen.xml b/app-timer-run/src/main/res/layout/activity_screen.xml
index 0db4ca29..05abda7a 100644
--- a/app-timer-run/src/main/res/layout/activity_screen.xml
+++ b/app-timer-run/src/main/res/layout/activity_screen.xml
@@ -7,10 +7,37 @@
android:background="?colorPrimarySurface"
tools:ignore="Overdraw">
+
+
+
+
-
-
-
-
diff --git a/component-key/src/main/java/xyz/aprildown/timer/component/key/behaviour/BehaviourLayoutUtils.kt b/component-key/src/main/java/xyz/aprildown/timer/component/key/behaviour/BehaviourLayoutUtils.kt
index 6e5f9713..7b0ba6d6 100644
--- a/component-key/src/main/java/xyz/aprildown/timer/component/key/behaviour/BehaviourLayoutUtils.kt
+++ b/component-key/src/main/java/xyz/aprildown/timer/component/key/behaviour/BehaviourLayoutUtils.kt
@@ -11,6 +11,7 @@ import xyz.aprildown.timer.domain.entities.toCountAction
import xyz.aprildown.timer.domain.entities.toHalfAction
import xyz.aprildown.timer.domain.entities.toMusicAction
import xyz.aprildown.timer.domain.entities.toNotificationAction
+import xyz.aprildown.timer.domain.entities.toScreenAction
import xyz.aprildown.timer.domain.entities.toVibrationAction
import xyz.aprildown.timer.domain.entities.toVoiceAction
import xyz.aprildown.timer.app.base.R as RBase
@@ -74,6 +75,9 @@ internal fun BehaviourEntity.getChipText(context: Context): String {
val duration = toNotificationAction().duration
if (duration != 0) "${getDefaultName()} $duration" else null
}
+ BehaviourType.SCREEN -> {
+ toScreenAction().title.ifBlank { null }
+ }
else -> null
} ?: getDefaultName()
}
diff --git a/domain/src/main/java/xyz/aprildown/timer/domain/entities/BehaviourEntity.kt b/domain/src/main/java/xyz/aprildown/timer/domain/entities/BehaviourEntity.kt
index 84efdf09..fa33bea9 100644
--- a/domain/src/main/java/xyz/aprildown/timer/domain/entities/BehaviourEntity.kt
+++ b/domain/src/main/java/xyz/aprildown/timer/domain/entities/BehaviourEntity.kt
@@ -137,15 +137,17 @@ fun BehaviourEntity.toVibrationAction(): VibrationAction {
// region Screen
-data class ScreenAction(val fullScreen: Boolean = false) : Action {
+data class ScreenAction(
+ val title: String = "", val uri: String = "", val fullScreen: Boolean = false
+) : Action {
override fun toBehaviourEntity(): BehaviourEntity {
- return BehaviourEntity(BehaviourType.SCREEN, str1 = if (fullScreen) "1" else "0")
+ return BehaviourEntity(BehaviourType.SCREEN, title, uri, fullScreen)
}
}
fun BehaviourEntity.toScreenAction(): ScreenAction {
require(type == BehaviourType.SCREEN)
- return ScreenAction(str1.toIntOrNull() == 1)
+ return ScreenAction(str1, str2, bool)
}
// endregion Screen
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 867533f8..41a2463d 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -2,6 +2,7 @@
agp = "8.0.2"
compileSdk = "33"
+glide = "4.12.0"
minSdk = "23"
targetSdk = "33"
@@ -33,8 +34,10 @@ secrets = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:2.0.1
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
[libraries]
+compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glide" }
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
desugarJdkLibs = "com.android.tools:desugar_jdk_libs:2.0.3"
+glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
tools = "com.github.DeweyReed:tools:0.7.0"
kotlin-coroutines-android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
diff --git a/presentation/src/main/java/xyz/aprildown/timer/presentation/stream/MachineContract.kt b/presentation/src/main/java/xyz/aprildown/timer/presentation/stream/MachineContract.kt
index c096185a..a8b1edcd 100644
--- a/presentation/src/main/java/xyz/aprildown/timer/presentation/stream/MachineContract.kt
+++ b/presentation/src/main/java/xyz/aprildown/timer/presentation/stream/MachineContract.kt
@@ -57,7 +57,7 @@ interface MachineContract {
fun startVibrating(pattern: LongArray, repeat: Boolean)
fun stopVibrating()
- fun showScreen(timerItem: TimerEntity, currentStepName: String, fullScreen: Boolean)
+ fun showScreen(timerItem: TimerEntity, currentStepName: String, fullScreen: Boolean, imagePath: String)
fun closeScreen()
// Halt is handled in the presenter
diff --git a/presentation/src/main/java/xyz/aprildown/timer/presentation/stream/MachinePresenter.kt b/presentation/src/main/java/xyz/aprildown/timer/presentation/stream/MachinePresenter.kt
index 0692589a..a9230dda 100644
--- a/presentation/src/main/java/xyz/aprildown/timer/presentation/stream/MachinePresenter.kt
+++ b/presentation/src/main/java/xyz/aprildown/timer/presentation/stream/MachinePresenter.kt
@@ -269,7 +269,7 @@ class MachinePresenter @Inject constructor(
// Handle screen first. This may help priority.
BehaviourType.SCREEN -> {
val action = behavior.toScreenAction()
- view?.showScreen(timer, currentStep.label, action.fullScreen)
+ view?.showScreen(timer, currentStep.label, action.fullScreen, action.uri)
}
BehaviourType.VIBRATION -> {
val action = behavior.toVibrationAction()