Setup adding/removing multiple timers

This commit is contained in:
Paul Akhamiogu 2021-08-31 21:18:45 +01:00
parent 49f0da8123
commit 921ca92885
14 changed files with 554 additions and 206 deletions

View File

@ -1,6 +1,7 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
@ -76,4 +77,6 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'org.greenrobot:eventbus:3.2.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.room:room-runtime:2.3.0'
kapt 'androidx.room:room-compiler:2.3.0'
}

View File

@ -0,0 +1,144 @@
package com.simplemobiletools.clock.adapters
import android.media.AudioManager
import android.media.RingtoneManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.simplemobiletools.clock.R
import com.simplemobiletools.clock.activities.SimpleActivity
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.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.models.AlarmSound
import kotlinx.android.synthetic.main.item_timer.view.*
import org.greenrobot.eventbus.EventBus
class TimerAdapter(
private val activity: SimpleActivity,
private val onRefresh: () -> Unit,
) : ListAdapter<Timer, TimerAdapter.TimerViewHolder>(diffUtil) {
private val config = activity.config
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TimerViewHolder {
return TimerViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_timer, parent, false))
}
override fun onBindViewHolder(holder: TimerViewHolder, position: Int) {
holder.bind(getItem(position))
}
fun getItemAt(position: Int): Timer {
return getItem(position)
}
inner class TimerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(timer: Timer) {
itemView.apply {
timer_time.text = timer.seconds.getFormattedDuration()
timer_label.setText(timer.label)
timer_time.text = timer.seconds.getFormattedDuration()
timer_label.setText(timer.label)
val textColor = activity.config.textColor
timer_initial_time.text = timer.seconds.getFormattedDuration()
timer_initial_time.colorLeftDrawable(textColor)
timer_vibrate.isChecked = timer.vibrate
timer_vibrate.colorLeftDrawable(textColor)
timer_sound.text = timer.soundTitle
timer_sound.colorLeftDrawable(textColor)
timer_time.setOnClickListener {
stopTimer(timer)
}
timer_time.setOnClickListener {
changeDuration(timer)
}
timer_initial_time.setOnClickListener {
changeDuration(timer)
}
timer_vibrate_holder.setOnClickListener {
timer_vibrate.toggle()
updateTimer(timer.copy(vibrate = timer_vibrate.isChecked), false)
}
timer_sound.setOnClickListener {
SelectAlarmSoundDialog(activity, config.timerSoundUri, AudioManager.STREAM_ALARM, PICK_AUDIO_FILE_INTENT_ID,
RingtoneManager.TYPE_ALARM, true,
onAlarmPicked = { sound ->
if (sound != null) {
updateAlarmSound(timer, sound)
}
},
onAlarmSoundDeleted = { sound ->
if (timer.soundUri == sound.uri) {
val defaultAlarm = context.getDefaultAlarmSound(RingtoneManager.TYPE_ALARM)
updateAlarmSound(timer, defaultAlarm)
}
context.checkAlarmsWithDeletedSoundUri(sound.uri)
})
}
timer_label.onTextChangeListener { text ->
updateTimer(timer.copy(label = text), false)
}
}
}
}
private fun stopTimer(timer: Timer) {
EventBus.getDefault().post(TimerState.Idle)
activity.hideTimerNotification()
}
private fun changeDuration(timer: Timer) {
MyTimePickerDialogDialog(activity, timer.seconds) { seconds ->
val timerSeconds = if (seconds <= 0) 10 else seconds
updateTimer(timer.copy(seconds = timerSeconds))
}
}
fun updateAlarmSound(timer: Timer, alarmSound: AlarmSound) {
updateTimer(timer.copy(soundTitle = alarmSound.title, soundUri = alarmSound.uri))
}
private fun updateTimer(timer: Timer, refresh: Boolean = true) {
activity.timerHelper.insertOrUpdateTimer(timer)
if (refresh) {
onRefresh.invoke()
}
}
companion object {
val diffUtil = object : DiffUtil.ItemCallback<Timer>() {
override fun areItemsTheSame(oldItem: Timer, newItem: Timer): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Timer, newItem: Timer): Boolean {
return oldItem == newItem
}
}
}
}

View File

@ -11,7 +11,6 @@ import com.simplemobiletools.clock.fragments.TimerFragment
import com.simplemobiletools.clock.helpers.TABS_COUNT
import com.simplemobiletools.clock.helpers.TAB_ALARM
import com.simplemobiletools.clock.helpers.TAB_CLOCK
import com.simplemobiletools.clock.helpers.TAB_TIMER
import com.simplemobiletools.commons.models.AlarmSound
class ViewPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
@ -51,6 +50,6 @@ class ViewPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
}
fun updateTimerTabAlarmSound(alarmSound: AlarmSound) {
(fragments[TAB_TIMER] as? TimerFragment)?.updateAlarmSound(alarmSound)
// (fragments[TAB_TIMER] as? TimerFragment)?.updateAlarmSound(alarmSound)
}
}

View File

@ -0,0 +1,38 @@
package com.simplemobiletools.clock.databases
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.simplemobiletools.clock.helpers.Converters
import com.simplemobiletools.clock.interfaces.TimerDao
import com.simplemobiletools.clock.models.Timer
@Database(entities = [Timer::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun TimerDao(): TimerDao
companion object {
private var db: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
if (db == null) {
synchronized(AppDatabase::class) {
if (db == null) {
db = Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "app.db")
.build()
db!!.openHelper.setWriteAheadLoggingEnabled(true)
}
}
}
return db!!
}
fun destroyInstance() {
db = null
}
}
}

View File

@ -20,7 +20,9 @@ import com.simplemobiletools.clock.R
import com.simplemobiletools.clock.activities.ReminderActivity
import com.simplemobiletools.clock.activities.SnoozeReminderActivity
import com.simplemobiletools.clock.activities.SplashActivity
import com.simplemobiletools.clock.databases.AppDatabase
import com.simplemobiletools.clock.helpers.*
import com.simplemobiletools.clock.interfaces.TimerDao
import com.simplemobiletools.clock.models.Alarm
import com.simplemobiletools.clock.models.MyTimeZone
import com.simplemobiletools.clock.receivers.AlarmReceiver
@ -39,6 +41,8 @@ import kotlin.math.pow
val Context.config: Config get() = Config.newInstance(applicationContext)
val Context.dbHelper: DBHelper get() = DBHelper.newInstance(applicationContext)
val Context.timerDb: TimerDao get() = AppDatabase.getInstance(applicationContext).TimerDao()
val Context.timerHelper: TimerHelper get() = TimerHelper(this)
fun Context.getFormattedDate(calendar: Calendar): String {
val dayOfWeek = (calendar.get(Calendar.DAY_OF_WEEK) + 5) % 7 // make sure index 0 means monday

View File

@ -1,31 +1,31 @@
package com.simplemobiletools.clock.fragments
import android.graphics.Color
import android.media.AudioManager
import android.media.RingtoneManager
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.dialogs.MyTimePickerDialogDialog
import com.simplemobiletools.clock.extensions.*
import com.simplemobiletools.clock.helpers.PICK_AUDIO_FILE_INTENT_ID
import com.simplemobiletools.clock.extensions.config
import com.simplemobiletools.clock.extensions.hideTimerNotification
import com.simplemobiletools.clock.extensions.timerHelper
import com.simplemobiletools.clock.models.Timer
import com.simplemobiletools.clock.models.TimerState
import com.simplemobiletools.commons.dialogs.SelectAlarmSoundDialog
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.models.AlarmSound
import kotlinx.android.synthetic.main.fragment_timer.view.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import kotlin.math.roundToInt
class TimerFragment : Fragment() {
lateinit var view: ViewGroup
private lateinit var timerAdapter: TimerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -39,91 +39,82 @@ class TimerFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
view = (inflater.inflate(R.layout.fragment_timer, container, false) as ViewGroup).apply {
val config = requiredActivity.config
val textColor = config.textColor
timerAdapter = TimerAdapter(requireActivity() as SimpleActivity) {
refreshTimers()
}
timer_view_pager.adapter = timerAdapter
timer_view_pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
updateViews(position)
}
})
timer_time.text = config.timerSeconds.getFormattedDuration()
timer_label.setText(config.timerLabel)
activity?.updateTextColors(timer_fragment)
timer_play_pause.background = resources.getColoredDrawableWithColor(R.drawable.circle_background_filled, requireContext().getAdjustedPrimaryColor())
timer_play_pause.applyColorFilter(if (requireContext().getAdjustedPrimaryColor() == Color.WHITE) Color.BLACK else Color.WHITE)
timer_reset.applyColorFilter(textColor)
timer_initial_time.text = config.timerSeconds.getFormattedDuration()
timer_initial_time.colorLeftDrawable(textColor)
timer_vibrate.isChecked = config.timerVibrate
timer_vibrate.colorLeftDrawable(textColor)
timer_sound.text = config.timerSoundTitle
timer_sound.colorLeftDrawable(textColor)
timer_time.setOnClickListener {
stopTimer()
timer_add.setOnClickListener {
activity?.hideKeyboard(it)
activity?.timerHelper?.insertNewTimer {
refreshTimers(true)
}
}
timer_play_pause.setOnClickListener {
val state = config.timerState
activity?.updateTextColors(timer_fragment)
when (state) {
is TimerState.Idle -> EventBus.getDefault().post(TimerState.Start(config.timerSeconds.secondsToMillis))
is TimerState.Paused -> EventBus.getDefault().post(TimerState.Start(state.tick))
is TimerState.Running -> EventBus.getDefault().post(TimerState.Pause(state.tick))
is TimerState.Finished -> EventBus.getDefault().post(TimerState.Start(config.timerSeconds.secondsToMillis))
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(TimerState.Start(timer.seconds.secondsToMillis))
// is TimerState.Paused -> EventBus.getDefault().post(TimerState.Start(state.tick))
// is TimerState.Running -> EventBus.getDefault().post(TimerState.Pause(state.tick))
// is TimerState.Finished -> EventBus.getDefault().post(TimerState.Start(timer.seconds.secondsToMillis))
else -> {
}
}
}
timer_reset.setOnClickListener {
stopTimer()
val timer = timerAdapter.getItemAt(timer_view_pager.currentItem)
stopTimer(timer)
}
timer_time.setOnClickListener {
changeDuration()
timer_delete.setOnClickListener {
val timer = timerAdapter.getItemAt(timer_view_pager.currentItem)
activity?.timerHelper?.deleteTimer(timer.id!!) {
refreshTimers()
}
}
timer_initial_time.setOnClickListener {
changeDuration()
}
timer_vibrate_holder.setOnClickListener {
timer_vibrate.toggle()
config.timerVibrate = timer_vibrate.isChecked
config.timerChannelId = null
}
timer_sound.setOnClickListener {
SelectAlarmSoundDialog(activity as SimpleActivity, config.timerSoundUri, AudioManager.STREAM_ALARM, PICK_AUDIO_FILE_INTENT_ID,
RingtoneManager.TYPE_ALARM, true,
onAlarmPicked = { sound ->
if (sound != null) {
updateAlarmSound(sound)
}
},
onAlarmSoundDeleted = { sound ->
if (config.timerSoundUri == sound.uri) {
val defaultAlarm = context.getDefaultAlarmSound(RingtoneManager.TYPE_ALARM)
updateAlarmSound(defaultAlarm)
}
context.checkAlarmsWithDeletedSoundUri(sound.uri)
})
}
timer_label.onTextChangeListener { text ->
config.timerLabel = text
}
refreshTimers()
}
return view
}
private fun stopTimer() {
private fun updateViews(position: Int) {
val timer = timerAdapter.getItemAt(position)
//check if timer is running to update view
}
private fun refreshTimers(scrollToLast: Boolean = false) {
activity?.timerHelper?.getTimers { timers ->
timerAdapter.submitList(timers)
activity?.runOnUiThread {
view.timer_delete.beVisibleIf(timers.size > 1)
if (scrollToLast) {
view.timer_view_pager.currentItem = timers.lastIndex
}
}
}
}
private fun stopTimer(timer: Timer) {
EventBus.getDefault().post(TimerState.Idle)
activity?.hideTimerNotification()
view.timer_time.text = activity?.config?.timerSeconds?.getFormattedDuration()
// view.timer_time.text = activity?.config?.timerSeconds?.getFormattedDuration()
}
private fun changeDuration() {
@ -131,23 +122,23 @@ class TimerFragment : Fragment() {
val timerSeconds = if (seconds <= 0) 10 else seconds
activity?.config?.timerSeconds = timerSeconds
val duration = timerSeconds.getFormattedDuration()
view.timer_initial_time.text = duration
// view.timer_initial_time.text = duration
if (view.timer_reset.isGone()) {
stopTimer()
}
// if (view.timer_reset.isGone()) {
// stopTimer()
// }
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(state: TimerState.Idle) {
view.timer_time.text = requiredActivity.config.timerSeconds.getFormattedDuration()
// view.timer_time.text = requiredActivity.config.timerSeconds.getFormattedDuration()
updateViewStates(state)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(state: TimerState.Running) {
view.timer_time.text = state.tick.div(1000F).roundToInt().getFormattedDuration()
// view.timer_time.text = state.tick.div(1000F).roundToInt().getFormattedDuration()
updateViewStates(state)
}
@ -158,7 +149,7 @@ class TimerFragment : Fragment() {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(state: TimerState.Finished) {
view.timer_time.text = 0.getFormattedDuration()
// view.timer_time.text = 0.getFormattedDuration()
updateViewStates(state)
}
@ -180,10 +171,10 @@ class TimerFragment : Fragment() {
view.timer_play_pause.setImageDrawable(resources.getColoredDrawableWithColor(drawableId, iconColor))
}
fun updateAlarmSound(alarmSound: AlarmSound) {
activity?.config?.timerSoundTitle = alarmSound.title
activity?.config?.timerSoundUri = alarmSound.uri
view.timer_sound.text = alarmSound.title
}
//
// fun updateAlarmSound(alarmSound: AlarmSound) {
// activity?.config?.timerSoundTitle = alarmSound.title
// activity?.config?.timerSoundUri = alarmSound.uri
// view.timer_sound.text = alarmSound.title
// }
}

View File

@ -1,7 +1,9 @@
package com.simplemobiletools.clock.helpers
import com.simplemobiletools.clock.models.MyTimeZone
import java.util.*
import java.util.Calendar
import java.util.Date
import java.util.TimeZone
import kotlin.math.pow
// shared preferences
@ -56,6 +58,8 @@ const val SORT_BY_ALARM_TIME = 1
const val TODAY_BIT = -1
const val TOMORROW_BIT = -2
const val DEFAULT_TIME = 300
fun getDefaultTimeZoneTitle(id: Int) = getAllTimeZones().firstOrNull { it.id == id }?.title ?: ""
fun getMSTillNextMinute(): Long {

View File

@ -0,0 +1,22 @@
package com.simplemobiletools.clock.helpers
import androidx.room.TypeConverter
import com.google.gson.Gson
import com.simplemobiletools.clock.models.StateWrapper
import com.simplemobiletools.clock.models.TimerState
class Converters {
private val gson = Gson()
@TypeConverter
fun jsonToTimerState(value: String): TimerState {
return try {
gson.fromJson(value, StateWrapper::class.java).state
} catch (e: Exception) {
TimerState.Idle
}
}
@TypeConverter
fun timerStateToJson(state: TimerState) = gson.toJson(StateWrapper(state))
}

View File

@ -0,0 +1,51 @@
package com.simplemobiletools.clock.helpers
import android.content.Context
import android.media.RingtoneManager
import com.simplemobiletools.clock.extensions.timerDb
import com.simplemobiletools.clock.models.Timer
import com.simplemobiletools.clock.models.TimerState
import com.simplemobiletools.commons.extensions.getDefaultAlarmSound
import com.simplemobiletools.commons.extensions.getDefaultAlarmTitle
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
class TimerHelper(val context: Context) {
private val timerDao = context.timerDb
fun getTimers(callback: (notes: List<Timer>) -> Unit) {
ensureBackgroundThread {
callback.invoke(timerDao.getTimers())
}
}
fun insertOrUpdateTimer(timer: Timer, callback: () -> Unit = {}) {
ensureBackgroundThread {
timerDao.insertOrUpdateTimer(timer)
callback.invoke()
}
}
fun deleteTimer(id: Long, callback: () -> Unit = {}) {
ensureBackgroundThread {
timerDao.deleteTimer(id)
callback.invoke()
}
}
fun insertNewTimer(callback: () -> Unit = {}) {
ensureBackgroundThread {
timerDao.insertOrUpdateTimer(
Timer(id = null,
seconds = DEFAULT_TIME,
TimerState.Idle,
false,
context.getDefaultAlarmSound(RingtoneManager.TYPE_ALARM).uri,
context.getDefaultAlarmTitle(RingtoneManager.TYPE_ALARM),
"",
DEFAULT_MAX_TIMER_REMINDER_SECS.toString())
)
callback.invoke()
}
}
}

View File

@ -0,0 +1,20 @@
package com.simplemobiletools.clock.interfaces
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.simplemobiletools.clock.models.Timer
@Dao
interface TimerDao {
@Query("SELECT * FROM timers")
fun getTimers(): List<Timer>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertOrUpdateTimer(timer: Timer): Long
@Query("DELETE FROM timers WHERE id=:id")
fun deleteTimer(id: Long)
}

View File

@ -0,0 +1,16 @@
package com.simplemobiletools.clock.models
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "timers")
data class Timer(
@PrimaryKey(autoGenerate = true) val id: Long?,
val seconds: Int,
val state: TimerState,
val vibrate: Boolean,
val soundUri: String,
val soundTitle: String,
val label: String,
val maxReminderSecs: String,
)

View File

@ -0,0 +1,11 @@
<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,127 +6,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="@+id/timer_scroll"
android:layout_width="0dp"
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/timer_view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/timer_play_pause"
android:layout_marginBottom="@dimen/medium_margin"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@id/timer_play_pause"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/timer_constraint"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/timer_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/normal_margin"
android:background="?attr/selectableItemBackground"
android:gravity="center_horizontal"
android:padding="@dimen/small_margin"
android:textSize="@dimen/stopwatch_text_size"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="00:00" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/timer_initial_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_margin"
android:background="?attr/selectableItemBackground"
android:drawableLeft="@drawable/ic_timer"
android:drawablePadding="@dimen/normal_margin"
android:padding="@dimen/activity_margin"
android:textSize="@dimen/bigger_text_size"
app:layout_constraintTop_toBottomOf="@+id/timer_time"
tools:text="05:00" />
<RelativeLayout
android:id="@+id/timer_vibrate_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="@dimen/activity_margin"
app:layout_constraintTop_toBottomOf="@+id/timer_initial_time">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/timer_vibrate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:drawableLeft="@drawable/ic_vibrate_vector"
android:drawablePadding="@dimen/normal_margin"
android:text="@string/vibrate"
android:textSize="@dimen/bigger_text_size" />
</RelativeLayout>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/timer_sound"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:drawableLeft="@drawable/ic_bell_vector"
android:drawablePadding="@dimen/normal_margin"
android:padding="@dimen/activity_margin"
android:textSize="@dimen/bigger_text_size"
app:layout_constraintTop_toBottomOf="@+id/timer_vibrate_holder"
tools:text="Default alarm" />
<LinearLayout
android:id="@+id/timer_label_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="@dimen/activity_margin"
android:paddingTop="@dimen/medium_margin"
android:paddingEnd="@dimen/activity_margin"
android:paddingBottom="@dimen/medium_margin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/timer_sound">
<ImageView
android:id="@+id/timer_label_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_label_vector" />
<com.simplemobiletools.commons.views.MyEditText
android:id="@+id/timer_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:hint="@string/label"
android:maxLines="1"
android:singleLine="true"
android:textCursorDrawable="@null"
android:textSize="@dimen/normal_text_size" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
<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: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_toTopOf="parent" />
<ImageView
android:id="@+id/timer_reset"
@ -140,8 +29,53 @@
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"
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" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
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:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/timer_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/normal_margin"
android:background="?attr/selectableItemBackground"
android:gravity="center_horizontal"
android:padding="@dimen/small_margin"
android:textSize="@dimen/stopwatch_text_size"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="00:00" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/timer_initial_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_margin"
android:background="?attr/selectableItemBackground"
android:drawableStart="@drawable/ic_timer"
android:drawablePadding="@dimen/normal_margin"
android:padding="@dimen/activity_margin"
android:textSize="@dimen/bigger_text_size"
app:layout_constraintTop_toBottomOf="@+id/timer_time"
tools:text="05:00" />
<RelativeLayout
android:id="@+id/timer_vibrate_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="@dimen/activity_margin"
app:layout_constraintTop_toBottomOf="@+id/timer_initial_time">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/timer_vibrate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:drawableStart="@drawable/ic_vibrate_vector"
android:drawablePadding="@dimen/normal_margin"
android:text="@string/vibrate"
android:textSize="@dimen/bigger_text_size" />
</RelativeLayout>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/timer_sound"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:drawableStart="@drawable/ic_bell_vector"
android:drawablePadding="@dimen/normal_margin"
android:padding="@dimen/activity_margin"
android:textSize="@dimen/bigger_text_size"
app:layout_constraintTop_toBottomOf="@+id/timer_vibrate_holder"
tools:text="Default alarm" />
<LinearLayout
android:id="@+id/timer_label_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="@dimen/activity_margin"
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"
app:layout_constraintVertical_bias="0"
app:layout_constraintVertical_chainStyle="spread_inside">
<ImageView
android:id="@+id/timer_label_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_label_vector" />
<com.simplemobiletools.commons.views.MyEditText
android:id="@+id/timer_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:hint="@string/label"
android:maxLines="1"
android:singleLine="true"
android:textCursorDrawable="@null"
android:textSize="@dimen/normal_text_size" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>