ref: change timer UI to use RecyclerView

- update commons library
This commit is contained in:
Paul Akhamiogu 2021-09-03 19:42:25 +01:00
parent 8d6b5770ed
commit 2e78d67529
38 changed files with 219 additions and 227 deletions

View File

@ -67,7 +67,7 @@ android {
}
dependencies {
implementation 'com.github.SimpleMobileTools:Simple-Commons:ac45c5e893'
implementation 'com.github.SimpleMobileTools:Simple-Commons:554dda71a4'
implementation 'com.facebook.stetho:stetho:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.shawnlin:number-picker:2.4.6'

View File

@ -1,5 +1,6 @@
package com.simplemobiletools.clock.adapters
import android.graphics.Color
import android.media.AudioManager
import android.media.RingtoneManager
import android.view.LayoutInflater
@ -14,13 +15,13 @@ import com.simplemobiletools.clock.dialogs.MyTimePickerDialogDialog
import com.simplemobiletools.clock.extensions.*
import com.simplemobiletools.clock.helpers.PICK_AUDIO_FILE_INTENT_ID
import com.simplemobiletools.clock.models.Timer
import com.simplemobiletools.clock.models.TimerEvent
import com.simplemobiletools.clock.models.TimerState
import com.simplemobiletools.commons.dialogs.SelectAlarmSoundDialog
import com.simplemobiletools.commons.extensions.getDefaultAlarmSound
import com.simplemobiletools.commons.extensions.getFormattedDuration
import com.simplemobiletools.commons.extensions.onTextChangeListener
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.models.AlarmSound
import kotlinx.android.synthetic.main.item_timer.view.*
import org.greenrobot.eventbus.EventBus
class TimerAdapter(
private val activity: SimpleActivity,
@ -39,6 +40,15 @@ class TimerAdapter(
}
}
private val config = activity.config
private var textColor = config.textColor
private var primaryColor = config.primaryColor
private var adjustedPrimaryColor = activity.getAdjustedPrimaryColor()
private var contrastColor = adjustedPrimaryColor.getContrastColor()
private var backgroundColor = config.backgroundColor
private var selectedTimer: Timer? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TimerViewHolder {
return TimerViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_timer, parent, false))
}
@ -47,52 +57,78 @@ class TimerAdapter(
holder.bind(getItem(position))
}
fun getItemAt(position: Int): Timer {
return getItem(position)
fun updateTextColor(textColor: Int) {
this.textColor = textColor
onRefresh.invoke()
}
fun updatePrimaryColor(primaryColor: Int) {
this.primaryColor = primaryColor
adjustedPrimaryColor = activity.getAdjustedPrimaryColor()
contrastColor = adjustedPrimaryColor.getContrastColor()
onRefresh.invoke()
}
inner class TimerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
init {
itemView.timer_label.onTextChangeListener { text ->
updateTimer(getItemAt(adapterPosition).copy(label = text), false)
updateTimer(getItem(adapterPosition).copy(label = text), false)
}
itemView.post {
val textColor = activity.config.textColor
itemView.timer_initial_time.colorLeftDrawable(textColor)
itemView.timer_vibrate.colorLeftDrawable(textColor)
itemView.timer_sound.colorLeftDrawable(textColor)
}
}
fun bind(timer: Timer) {
itemView.apply {
post {
timer_initial_time.colorLeftDrawable(textColor)
timer_vibrate.colorLeftDrawable(textColor)
timer_label_image.applyColorFilter(textColor)
timer_sound.colorLeftDrawable(textColor)
timer_play_pause.background = activity.resources.getColoredDrawableWithColor(R.drawable.circle_background_filled, adjustedPrimaryColor)
timer_play_pause.applyColorFilter(if (adjustedPrimaryColor == Color.WHITE) Color.BLACK else Color.WHITE)
timer_reset.applyColorFilter(textColor)
timer_delete.applyColorFilter(textColor)
}
timer_label.setTextColor(textColor)
timer_label.setHintTextColor(textColor.adjustAlpha(0.7f))
//only update when different to prevent flickering and unnecessary updates
if (timer_label.text.toString() != timer.label) {
timer_label.setText(timer.label)
}
timer_initial_time.text = timer.seconds.getFormattedDuration()
timer_initial_time.setTextColor(textColor)
timer_vibrate.isChecked = timer.vibrate
timer_vibrate.setTextColor(textColor)
timer_vibrate.setColors(textColor, adjustedPrimaryColor, backgroundColor)
timer_vibrate_holder.setOnClickListener {
timer_vibrate.toggle()
updateTimer(timer.copy(vibrate = timer_vibrate.isChecked, channelId = null), false)
}
timer_sound.text = timer.soundTitle
timer_time.setTextColor(textColor)
timer_time.text = when (timer.state) {
is TimerState.Finished -> 0.getFormattedDuration()
is TimerState.Idle -> timer.seconds.getFormattedDuration()
is TimerState.Paused -> timer.state.tick.getFormattedDuration()
is TimerState.Running -> timer.state.tick.getFormattedDuration()
}
timer_time.setOnClickListener {
changeDuration(timer)
}
timer_initial_time.setTextColor(textColor)
timer_initial_time.setOnClickListener {
changeDuration(timer)
}
timer_vibrate_holder.setOnClickListener {
timer_vibrate.toggle()
updateTimer(timer.copy(vibrate = timer_vibrate.isChecked), false)
}
timer_sound.text = timer.soundTitle
timer_sound.setTextColor(textColor)
timer_sound.setOnClickListener {
selectedTimer = timer
SelectAlarmSoundDialog(activity, timer.soundUri, AudioManager.STREAM_ALARM, PICK_AUDIO_FILE_INTENT_ID,
RingtoneManager.TYPE_ALARM, true,
onAlarmPicked = { sound ->
@ -110,25 +146,38 @@ class TimerAdapter(
})
}
when (timer.state) {
is TimerState.Finished -> {
timer_time.text = 0.getFormattedDuration()
timer_delete.applyColorFilter(textColor)
timer_delete.setOnClickListener {
activity.timerHelper.deleteTimer(timer.id!!) {
onRefresh.invoke()
}
}
is TimerState.Idle -> {
timer_time.text = timer.seconds.getFormattedDuration()
timer_reset.applyColorFilter(textColor)
timer_reset.setOnClickListener {
stopTimer(timer)
}
is TimerState.Paused -> {
timer_time.text = timer.state.tick.getFormattedDuration()
timer_play_pause.setOnClickListener {
when (val state = timer.state) {
is TimerState.Idle -> EventBus.getDefault().post(TimerEvent.Start(timer.id!!, timer.seconds.secondsToMillis))
is TimerState.Paused -> EventBus.getDefault().post(TimerEvent.Start(timer.id!!, state.tick))
is TimerState.Running -> EventBus.getDefault().post(TimerEvent.Pause(timer.id!!, state.tick))
is TimerState.Finished -> EventBus.getDefault().post(TimerEvent.Start(timer.id!!, timer.seconds.secondsToMillis))
}
}
updateViewStates(timer.state)
}
}
is TimerState.Running -> {
timer_time.text = timer.state.tick.getFormattedDuration()
}
}
}
private fun updateViewStates(state: TimerState) {
val resetPossible = state is TimerState.Running || state is TimerState.Paused || state is TimerState.Finished
itemView.timer_reset.beInvisibleIf(!resetPossible)
itemView.timer_delete.beInvisibleIf(!(!resetPossible && itemCount > 1))
val drawableId = if (state is TimerState.Running) R.drawable.ic_pause_vector else R.drawable.ic_play_vector
val iconColor = if (adjustedPrimaryColor == Color.WHITE) Color.BLACK else Color.WHITE
itemView.timer_play_pause.setImageDrawable(activity.resources.getColoredDrawableWithColor(drawableId, iconColor))
}
}
@ -139,6 +188,10 @@ class TimerAdapter(
}
}
fun updateAlarmSoundForSelectedTimer(alarmSound: AlarmSound) {
selectedTimer?.let { updateAlarmSound(it, alarmSound) }
}
fun updateAlarmSound(timer: Timer, alarmSound: AlarmSound) {
updateTimer(timer.copy(soundTitle = alarmSound.title, soundUri = alarmSound.uri, channelId = null))
}
@ -150,4 +203,10 @@ class TimerAdapter(
}
}
}
private fun stopTimer(timer: Timer) {
EventBus.getDefault().post(TimerEvent.Reset(timer.id!!, timer.seconds.secondsToMillis))
activity.hideTimerNotification()
}
}

View File

@ -1,26 +1,22 @@
package com.simplemobiletools.clock.fragments
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.viewpager2.widget.ViewPager2
import com.simplemobiletools.clock.R
import com.simplemobiletools.clock.activities.SimpleActivity
import com.simplemobiletools.clock.adapters.TimerAdapter
import com.simplemobiletools.clock.extensions.config
import com.simplemobiletools.clock.extensions.hideTimerNotification
import com.simplemobiletools.clock.extensions.secondsToMillis
import com.simplemobiletools.clock.extensions.timerHelper
import com.simplemobiletools.clock.models.Timer
import com.simplemobiletools.clock.models.TimerEvent
import com.simplemobiletools.clock.models.TimerState
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.extensions.hideKeyboard
import com.simplemobiletools.commons.extensions.updateTextColors
import com.simplemobiletools.commons.models.AlarmSound
import kotlinx.android.synthetic.main.fragment_timer.timer_view_pager
import kotlinx.android.synthetic.main.fragment_timer.view.*
import kotlinx.android.synthetic.main.fragment_timer.timer_fragment
import kotlinx.android.synthetic.main.fragment_timer.view.timer_add
import kotlinx.android.synthetic.main.fragment_timer.view.timers_list
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@ -30,6 +26,7 @@ class TimerFragment : Fragment() {
private lateinit var view: ViewGroup
private lateinit var timerAdapter: TimerAdapter
private var timerPositionToScrollTo = INVALID_POSITION
private var storedTextColor = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -47,22 +44,10 @@ class TimerFragment : Fragment() {
refreshTimers()
}
timer_view_pager.adapter = timerAdapter
//set empty page transformer to disable item animations
timer_view_pager.setPageTransformer { _, _ -> }
timer_view_pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
updateViews(position)
}
})
activity?.let {
val textColor = it.config.textColor
indicator_view.setSelectedDotColor(textColor)
indicator_view.setDotColor(textColor.adjustAlpha(0.5f))
indicator_view.attachToPager(timer_view_pager)
}
storeStateVariables()
timers_list.adapter = timerAdapter
timers_list.itemAnimator = null
timer_add.setOnClickListener {
activity?.hideKeyboard(it)
@ -71,70 +56,43 @@ class TimerFragment : Fragment() {
}
}
activity?.updateTextColors(timer_fragment)
val textColor = requireContext().config.textColor
timer_play_pause.background =
resources.getColoredDrawableWithColor(R.drawable.circle_background_filled, requireActivity().getAdjustedPrimaryColor())
timer_play_pause.applyColorFilter(if (activity?.getAdjustedPrimaryColor() == Color.WHITE) Color.BLACK else Color.WHITE)
timer_reset.applyColorFilter(textColor)
timer_play_pause.setOnClickListener {
val timer = timerAdapter.getItemAt(timer_view_pager.currentItem)
when (val state = timer.state) {
is TimerState.Idle -> EventBus.getDefault().post(TimerEvent.Start(timer.id!!, timer.seconds.secondsToMillis))
is TimerState.Paused -> EventBus.getDefault().post(TimerEvent.Start(timer.id!!, state.tick))
is TimerState.Running -> EventBus.getDefault().post(TimerEvent.Pause(timer.id!!, state.tick))
is TimerState.Finished -> EventBus.getDefault().post(TimerEvent.Start(timer.id!!, timer.seconds.secondsToMillis))
}
}
timer_reset.setOnClickListener {
val timer = timerAdapter.getItemAt(timer_view_pager.currentItem)
stopTimer(timer)
}
timer_delete.setOnClickListener {
val timer = timerAdapter.getItemAt(timer_view_pager.currentItem)
activity?.timerHelper?.deleteTimer(timer.id!!) {
refreshTimers()
}
}
refreshTimers()
}
return view
}
private fun updateViews(position: Int) {
activity?.runOnUiThread {
if (timerAdapter.itemCount > position) {
val timer = timerAdapter.getItemAt(position)
updateViewStates(timer.state)
view.timer_play_pause.beVisible()
override fun onResume() {
super.onResume()
requireContext().updateTextColors(timer_fragment)
val configTextColor = requireContext().config.textColor
if (storedTextColor != configTextColor) {
(view.timers_list.adapter as TimerAdapter).updateTextColor(configTextColor)
}
}
override fun onPause() {
super.onPause()
storeStateVariables()
}
private fun refreshTimers(scrollToLatest: Boolean = false) {
activity?.timerHelper?.getTimers { timers ->
timerAdapter.submitList(timers) {
view.timer_view_pager.post {
view.timers_list.post {
if (timerPositionToScrollTo != INVALID_POSITION && timerAdapter.itemCount > timerPositionToScrollTo) {
view.timer_view_pager.setCurrentItem(timerPositionToScrollTo, false)
view.timers_list.scrollToPosition(timerPositionToScrollTo)
timerPositionToScrollTo = INVALID_POSITION
} else if (scrollToLatest) {
view.timer_view_pager.setCurrentItem(0, false)
view.timers_list.scrollToPosition(timers.lastIndex)
}
updateViews(timer_view_pager.currentItem)
}
}
}
}
private fun stopTimer(timer: Timer) {
EventBus.getDefault().post(TimerEvent.Reset(timer.id!!, timer.seconds.secondsToMillis))
activity?.hideTimerNotification()
private fun storeStateVariables() {
storedTextColor = requireContext().config.textColor
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -142,31 +100,8 @@ class TimerFragment : Fragment() {
refreshTimers()
}
private fun updateViewStates(state: TimerState) {
val resetPossible = state is TimerState.Running || state is TimerState.Paused || state is TimerState.Finished
view.timer_reset.beInvisibleIf(!resetPossible)
view.timer_delete.beInvisibleIf(!(!resetPossible && timerAdapter.itemCount > 1))
val drawableId = if (state is TimerState.Running) {
R.drawable.ic_pause_vector
} else {
R.drawable.ic_play_vector
}
val iconColor = if (activity?.getAdjustedPrimaryColor() == Color.WHITE) {
Color.BLACK
} else {
Color.WHITE
}
view.timer_play_pause.setImageDrawable(resources.getColoredDrawableWithColor(drawableId, iconColor))
}
fun updateAlarmSound(alarmSound: AlarmSound) {
val timer = timerAdapter.getItemAt(timer_view_pager.currentItem)
activity?.timerHelper?.insertOrUpdateTimer(timer.copy(soundTitle = alarmSound.title, soundUri = alarmSound.uri)) {
refreshTimers()
}
timerAdapter.updateAlarmSoundForSelectedTimer(alarmSound)
}
fun updatePosition(timerId: Long) {
@ -175,7 +110,7 @@ class TimerFragment : Fragment() {
if (position != INVALID_POSITION) {
activity?.runOnUiThread {
if (timerAdapter.itemCount > position) {
view.timer_view_pager.setCurrentItem(position, false)
view.timers_list.scrollToPosition(position)
} else {
timerPositionToScrollTo = position
}

View File

@ -51,7 +51,6 @@ class TimerHelper(val context: Context) {
channelId = config.timerChannelId,
)
)
callback.invoke()
}
}

View File

@ -9,7 +9,7 @@ import com.simplemobiletools.clock.models.Timer
@Dao
interface TimerDao {
@Query("SELECT * FROM timers ORDER BY createdAt DESC")
@Query("SELECT * FROM timers ORDER BY createdAt ASC")
fun getTimers(): List<Timer>
@Query("SELECT * FROM timers WHERE id=:id")

View File

@ -49,15 +49,9 @@ class TimerService : Service() {
val firstTimer = runningTimers.first()
val formattedDuration = (firstTimer.state as TimerState.Running).tick.getFormattedDuration()
val contextText = when {
runningTimers.size > 1 -> {
getString(R.string.timer_multiple_notification_msg, runningTimers.size)
}
firstTimer.label.isNotEmpty() -> {
getString(R.string.timer_single_notification_label_msg, firstTimer.label)
}
else -> {
getString(R.string.timer_single_notification_msg, runningTimers.size)
}
runningTimers.size > 1 -> getString(R.string.timer_multiple_notification_msg, runningTimers.size)
firstTimer.label.isNotEmpty() -> getString(R.string.timer_single_notification_label_msg, firstTimer.label)
else -> getString(R.string.timer_single_notification_msg, runningTimers.size)
}
startForeground(TIMER_RUNNING_NOTIF_ID, notification(formattedDuration, contextText, firstTimer.id!!))
}

View File

@ -1,11 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"
android:strokeWidth="1.6"
android:strokeColor="#FFFFFFFF" />
</vector>

View File

@ -6,87 +6,32 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/timer_view_pager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="@dimen/medium_margin"
android:layout_marginBottom="@dimen/medium_margin"
<com.simplemobiletools.commons.views.MyRecyclerView
android:id="@+id/timers_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@id/timer_play_pause"
app:layout_constraintEnd_toStartOf="@id/indicator_view"
android:paddingBottom="@dimen/fab_list_bottom_padding"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
tools:itemCount="3"
tools:listitem="@layout/item_timer" />
<com.simplemobiletools.clock.views.pageindicator.PagerIndicator
android:id="@+id/indicator_view"
<com.simplemobiletools.commons.views.MyFloatingActionButton
android:id="@+id/timer_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/medium_margin"
app:layout_constraintBottom_toTopOf="@id/timer_play_pause"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.05"
app:spi_orientation="vertical" />
<ImageView
android:id="@+id/timer_reset"
android:layout_width="@dimen/stopwatch_button_small_size"
android:layout_height="@dimen/stopwatch_button_small_size"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_reset_vector"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/timer_play_pause"
app:layout_constraintEnd_toStartOf="@+id/timer_play_pause"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/timer_play_pause"
tools:visibility="gone" />
<ImageView
android:id="@+id/timer_delete"
android:layout_width="@dimen/stopwatch_button_small_size"
android:layout_height="@dimen/stopwatch_button_small_size"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_delete_vector"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/timer_play_pause"
app:layout_constraintEnd_toStartOf="@+id/timer_play_pause"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/timer_play_pause"
tools:visibility="visible" />
<ImageView
android:id="@+id/timer_play_pause"
android:layout_width="@dimen/stopwatch_button_size"
android:layout_height="@dimen/stopwatch_button_size"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/big_margin"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/activity_margin"
android:src="@drawable/ic_play_vector"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/activity_margin"
android:contentDescription="@string/new_timer"
android:src="@drawable/ic_plus_vector"
app:backgroundTint="@color/color_primary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/timer_add"
android:layout_width="@dimen/stopwatch_button_size"
android:layout_height="@dimen/stopwatch_button_size"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/big_margin"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/activity_margin"
android:src="@drawable/ic_add_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/timer_play_pause" />
app:rippleColor="@color/pressed_item_foreground" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/timer_time"
@ -75,7 +75,6 @@
android:paddingTop="@dimen/medium_margin"
android:paddingEnd="@dimen/activity_margin"
android:paddingBottom="@dimen/medium_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/timer_sound"
@ -100,4 +99,47 @@
android:textSize="@dimen/normal_text_size" />
</LinearLayout>
<ImageView
android:id="@+id/timer_reset"
android:layout_width="@dimen/stopwatch_button_small_size"
android:layout_height="@dimen/stopwatch_button_small_size"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_reset_vector"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/timer_play_pause"
app:layout_constraintEnd_toStartOf="@+id/timer_play_pause"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/timer_play_pause" />
<ImageView
android:id="@+id/timer_delete"
android:layout_width="@dimen/stopwatch_button_small_size"
android:layout_height="@dimen/stopwatch_button_small_size"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_delete_vector"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/timer_play_pause"
app:layout_constraintEnd_toStartOf="@+id/timer_play_pause"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/timer_play_pause"
tools:visibility="visible" />
<ImageView
android:id="@+id/timer_play_pause"
android:layout_width="@dimen/stopwatch_button_size"
android:layout_height="@dimen/stopwatch_button_size"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/big_margin"
android:layout_marginBottom="@dimen/big_margin"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/activity_margin"
android:src="@drawable/ic_play_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/timer_label_holder" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Saat bölməsi</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Záložka hodin</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Tab cloc</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Ur</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Uhr</string>

View File

@ -23,6 +23,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Ετικέτα Ρολογιού</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Pestaña de reloj</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Erloju fitxa</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
 
<!-- Settings -->
<string name="clock_tab">Kello-välilehti</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Horloge</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Kartica sata</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Tab jam</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Tab jam</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Scheda orologio</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">時計</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Laikrodžio skirtukas</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">ക്ലോക്ക് ടാബ്</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Klokke</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Tab Klok</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Zegar</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Relógio</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Часы</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Okno s časom</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Fliken Klocka</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Saat sekmesi</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Годинник</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">时钟页面</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">時鐘頁面</string>

View File

@ -22,6 +22,7 @@
<string name="timer_multiple_notification_msg">%d timers are running</string>
<string name="timer_single_notification_label_msg">Timer for %s is running</string>
<string name="timer_single_notification_msg">%d timer is running</string>
<string name="new_timer">New Timer</string>
<!-- Settings -->
<string name="clock_tab">Clock tab</string>