diff --git a/app/build.gradle b/app/build.gradle index 5ad72cd..8beadf1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { defaultConfig { applicationId "iam.thevoid.epic.timeapp" - minSdk 21 + minSdk 26 targetSdk 31 versionCode 1 versionName "1.0" diff --git a/app/src/main/java/iam/thevoid/epic/timeapp/MainActivity.kt b/app/src/main/java/iam/thevoid/epic/timeapp/MainActivity.kt index d08be6e..df2a40c 100644 --- a/app/src/main/java/iam/thevoid/epic/timeapp/MainActivity.kt +++ b/app/src/main/java/iam/thevoid/epic/timeapp/MainActivity.kt @@ -1,10 +1,20 @@ package iam.thevoid.epic.timeapp -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.util.Log import android.widget.Button import android.widget.EditText import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.Observable +import io.reactivex.rxjava3.schedulers.Schedulers +import java.time.Instant +import java.time.LocalTime +import java.time.format.DateTimeFormatter +import java.util.concurrent.TimeUnit +import kotlin.time.DurationUnit +import kotlin.time.toDuration // Дан экран с готовой разметкой // Реализовать при помощи RxJava @@ -28,19 +38,21 @@ import android.widget.TextView class MainActivity : AppCompatActivity() { + private val TAG = this::class.simpleName + // Часы: private lateinit var clockText: TextView // Обратный отсчёт - private lateinit var countdownText: TextView - private lateinit var countdownSecondsEditText: EditText - private lateinit var countdownStartButton: Button + private lateinit var countDownText: TextView + private lateinit var countDownSecondsEditText: EditText + private lateinit var countDownStartButton: Button // Секундомер - private lateinit var stopwatchText: TextView - private lateinit var stopwatchMillisText: TextView - private lateinit var stopwatchStartButton: EditText - private lateinit var stopwatchEndButton: EditText + private lateinit var stopWatchText: TextView + private lateinit var stopWatchMillisText: TextView + private lateinit var stopWatchStartButton: Button + private lateinit var stopWatchEndButton: Button override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -48,13 +60,151 @@ class MainActivity : AppCompatActivity() { clockText = findViewById(R.id.clockText) - countdownText = findViewById(R.id.countdownText) - countdownSecondsEditText = findViewById(R.id.countdownEditText) - countdownStartButton = findViewById(R.id.countdownStartButton) + countDownText = findViewById(R.id.countdownText) + countDownSecondsEditText = findViewById(R.id.countdownEditText) + countDownStartButton = findViewById(R.id.countdownStartButton) + + stopWatchText = findViewById(R.id.stopwatchText) + stopWatchMillisText = findViewById(R.id.stopwatchMillisText) + stopWatchStartButton = findViewById(R.id.stopwatchStartButton) + stopWatchEndButton = findViewById(R.id.stopwatchEndButton) + + + // 1. Часы + clock() + + // 2. Таймер + displayCountDown(0) // Начальное значение + timer() + + + // 3. Секундомер + displayStopWatch() // Начальное значение + stopWatch() + } + + private fun clock() { + Observable.interval(1, TimeUnit.SECONDS, Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + + .subscribe { + clockText.text = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) + } + } + + private val delimiter = ":" + + private val twoDigits: (Number) -> String = + { value -> if (value.toLong() < 10) "0$value" else "$value" } + + private val formatTime: (Long, Int, Int, Int) -> java.lang.StringBuilder = + { hours, minutes, seconds, nano -> + StringBuilder() + .append(twoDigits(hours)) + .append(delimiter) + .append(twoDigits(minutes)) + .append(delimiter) + .append(twoDigits(seconds)) + } + + private val displayCountDown: (Long) -> Unit = + { seconds -> + countDownText.text = + seconds.toDuration(DurationUnit.SECONDS).toComponents(formatTime) + } + + private fun timer() { + val countDownValue: () -> Long = + { countDownSecondsEditText.text.toString().toLongOrNull() ?: 0L } + + countDownStartButton.setOnClickListener { + val seconds = countDownValue() + Log.i(TAG, "seconds: $seconds") + + if (seconds > 0) { + // Время окончания + val end = Instant.now().plusSeconds(seconds) + + Observable.interval(1, TimeUnit.SECONDS, Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + + .takeWhile { Instant.now() <= end } + + .subscribe { + val remained = end.minusMillis(Instant.now().toEpochMilli()) + val duration = + remained.toEpochMilli().toDuration(DurationUnit.MILLISECONDS) + countDownText.text = duration.toComponents(formatTime) + } + } + } + } + + private enum class EStopWatchStatus { + STOP, + RUN, + PAUSE + } + + private object stopWatchStatus { + var status: EStopWatchStatus = EStopWatchStatus.STOP + var value: Long = 0 + } + + private val displayStopWatch: () -> Unit = { + stopWatchText.text = + stopWatchStatus.value.toDuration(DurationUnit.MILLISECONDS) + .toComponents(formatTime) + stopWatchMillisText.text = + "${stopWatchStatus.value % 1000 / 100}" // 10-е мс + } + + private fun stopWatch() { + stopWatchStartButton.setOnClickListener { + Log.i(TAG, "${stopWatchStatus.status}: ${stopWatchStatus.value}") + + if (stopWatchStatus.status == EStopWatchStatus.STOP || stopWatchStatus.status == EStopWatchStatus.PAUSE) { + stopWatchStatus.status = EStopWatchStatus.RUN // Начинаем работу + + stopWatchEndButton.text = "Пауза" + + val start = Instant.now() + .toEpochMilli() - stopWatchStatus.value // При состоянии паузы "отходим назад" + + Observable.interval(100, TimeUnit.MILLISECONDS, Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + + .takeWhile { stopWatchStatus.status == EStopWatchStatus.RUN } + + .subscribe { + stopWatchStatus.value = Instant.now().toEpochMilli() - start + displayStopWatch() + } + } + } + + stopWatchEndButton.setOnClickListener() + { + Log.i(TAG, "${stopWatchStatus.status}: ${stopWatchStatus.value}") + when (stopWatchStatus.status) { + EStopWatchStatus.RUN -> { + // Приостанавливаем + stopWatchStatus.status = EStopWatchStatus.PAUSE + stopWatchEndButton.text = "Сброс" + } + EStopWatchStatus.PAUSE -> { + // Сброс + stopWatchStatus.status = EStopWatchStatus.STOP + stopWatchStatus.value = 0 + + stopWatchEndButton.text = "Пауза" - stopwatchText = findViewById(R.id.stopwatchText) - stopwatchMillisText = findViewById(R.id.stopwatchMillisText) - stopwatchStartButton = findViewById(R.id.stopwatchStartButton) - stopwatchEndButton = findViewById(R.id.stopwatchEndButton) + displayStopWatch() + } + EStopWatchStatus.STOP -> { + stopWatchEndButton.text = "Пауза" + } + } + } } -} \ No newline at end of file +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 81ade1e..e395997 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -65,7 +65,7 @@ android:id="@+id/countdownStartButton" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="Start" /> + android:text="Старт" /> + android:text="Старт" /> + android:text="Пауза" /> diff --git a/build.gradle b/build.gradle index 84ed49d..0ccd671 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '7.1.1' apply false - id 'com.android.library' version '7.1.1' apply false + id 'com.android.application' version '7.1.2' apply false + id 'com.android.library' version '7.1.2' apply false id 'org.jetbrains.kotlin.android' version '1.6.10' apply false }