Skip to content
Closed
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
1 change: 1 addition & 0 deletions app-base/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@

<string name="behaviour_screen">Screen</string>
<string name="behaviour_screen_help">Wake up the phone and show a reminding screen</string>
<string name="screen_pick_image">Pick Step Image</string>
<string name="screen_fullscreen">Always Fullscreen</string>

<string name="behaviour_halt">Halt</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -179,6 +182,35 @@ class UpdateStepDialog :
addScreenItems(
context = context,
action = current.toScreenAction(),
onPickImageClick = {
registerForActivityResult(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registering a launcher after onCreate will crash the app. If I remember correctly, you must create the launcher before or in onCreate.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I indeed noticed that with "EditActivity.kt", which has this fixed. I leaved it that way here because I didn't know how to accommodate the difference between this file and the other. Beside, I still don't know when this file intervenes in the app

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()
Expand Down
2 changes: 2 additions & 0 deletions app-timer-run/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ dependencies {
implementation libs.hilt.android
kapt libs.hilt.compiler

implementation libs.glide
annotationProcessor libs.compiler

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler is redundant here because we only use Glide to load images.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad. I admit this one was a blind copy-pasting of some tutorial

}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Action>()
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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))
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glide can take care of everything for you, like this:
Glide.with(this).load(imagePath.toUri()).into(binding.image)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know. Thanks!

viewModel.setTimerId(
intent?.getIntExtra(Constants.EXTRA_TIMER_ID, TimerEntity.NULL_ID)
?: TimerEntity.NULL_ID
Expand Down Expand Up @@ -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()
}

Expand All @@ -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)
}
}
}
73 changes: 28 additions & 45 deletions app-timer-run/src/main/res/layout-land/activity_screen.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,84 +9,67 @@

<TextView
android:id="@+id/textStepInfo"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_width="191dp"
android:layout_height="113dp"
android:layout_marginTop="16dp"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Designing layouts with the layout inspector makes the layout inconsistent on different devices, which is why many developers prefer XML.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't know using the layout designer was known to be a problem. Will remember this next time I work on native Android project

android:textColor="?colorOnPrimarySurface"
android:textSize="24sp"
app:autoSizeMaxTextSize="24sp"
app:autoSizeTextType="uniform"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/textTime"
app:layout_constraintStart_toStartOf="@id/textTime"
app:layout_constraintTop_toBottomOf="@id/textTime"
app:layout_constraintVertical_bias="0"
app:layout_constraintTop_toBottomOf="@+id/textTime"
tools:layout_editor_absoluteX="16dp"
tools:text="@tools:sample/lorem/random" />

<ImageView
android:id="@+id/imageRingtone"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="32dp"
android:id="@+id/image"
android:layout_width="384dp"
android:layout_height="368dp"
android:layout_marginStart="14dp"
android:layout_marginEnd="20dp"
android:importantForAccessibility="no"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/btnStop"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/textTime"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_anim_ringing"
app:tint="?colorOnPrimarySurface" />
android:scaleType="center"
app:layout_constraintEnd_toStartOf="@+id/btnStop"
app:layout_constraintStart_toEndOf="@+id/textStepInfo"
tools:layout_editor_absoluteY="21dp" />

<TextView
android:id="@+id/textTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginBottom="8dp"
android:layout_width="188dp"
android:layout_height="104dp"
android:layout_marginTop="21dp"
android:fontFamily="@font/digital_numbers_colon"
android:maxLines="1"
android:paddingTop="24dp"
android:paddingBottom="24dp"
android:textColor="?colorOnPrimarySurface"
android:textSize="108sp"
app:autoSizeTextType="uniform"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/imageRingtone"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnAddOneMinute"
tools:layout_editor_absoluteX="16dp"
tools:text="12:34" />

<Button
android:id="@+id/btnAddOneMinute"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="@string/one_action_add_one_minute"
android:textColor="?colorOnPrimarySurface"
app:layout_constraintBottom_toTopOf="@id/textTime"
app:layout_constraintStart_toStartOf="parent"
app:rippleColor="?colorOnPrimarySurface" />
app:rippleColor="?colorOnPrimarySurface"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="16dp" />

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_width="90dp"
android:layout_height="124dp"
android:contentDescription="@string/stop"
app:fabCustomSize="156dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/imageRingtone"
app:layout_constraintTop_toTopOf="parent"
app:fabCustomSize="94dp"
app:maxImageSize="72dp"
app:srcCompat="@drawable/ic_stop" />
app:srcCompat="@drawable/ic_stop"
tools:layout_editor_absoluteX="625dp"
tools:layout_editor_absoluteY="165dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

Loading