diff --git a/README.md b/README.md
index 11b392d3..3609c49e 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@ In addition to this, other useful features are also available:
* analysis of collected data (for visual acuity test);
* import and export of the journal to a file;
* setting the correct image scaling during tests;
+* light and dark themes with auto/manual selection;
* support for Russian and English languages.
## Screenshots
@@ -54,4 +55,4 @@ This project uses:
* [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) (charts)
* [ViewBindingPropertyDelegate](https://github.com/kirich1409/ViewBindingPropertyDelegate) (view binding)
* [ObjectBox](https://github.com/objectbox/objectbox-java) (database)
-* [JUnit 5](https://junit.org/junit5/) (testing)
\ No newline at end of file
+* [JUnit 5](https://github.com/junit-team/junit5) + [Mockito](https://github.com/mockito/mockito) (testing)
\ No newline at end of file
diff --git a/README.ru.md b/README.ru.md
index 099e6aa2..70b0a134 100644
--- a/README.ru.md
+++ b/README.ru.md
@@ -28,6 +28,7 @@
* анализ собранных данных (для теста остроты зрения);
* импорт и экспорт журнала в файл;
* настройка правильного масштабирования изображения во время тестов;
+* светлая и темная темы с авто/ручным выбором;
* поддержка русского и английского языков.
## Скриншоты
@@ -54,4 +55,4 @@
* [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) (графики)
* [ViewBindingPropertyDelegate](https://github.com/kirich1409/ViewBindingPropertyDelegate) (view binding)
* [ObjectBox](https://github.com/objectbox/objectbox-java) (база данных)
-* [JUnit 5](https://junit.org/junit5/) (тестирование)
\ No newline at end of file
+* [JUnit 5](https://github.com/junit-team/junit5) + [Mockito](https://github.com/mockito/mockito) (тестирование)
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 058d5f72..381bd2ec 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -110,6 +110,12 @@ android {
abi.enableSplit = false
language.enableSplit = false
}
+ @Suppress("UnstableApiUsage")
+ testOptions {
+ unitTests.all {
+ it.useJUnitPlatform()
+ }
+ }
}
dependencies {
@@ -125,7 +131,7 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
- implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
+ implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
implementation("androidx.preference:preference-ktx:1.2.1")
implementation("androidx.viewpager2:viewpager2:1.1.0-beta02")
@@ -136,6 +142,7 @@ dependencies {
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:" + rootProject.extra["coroutinesVersion"])
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:" + rootProject.extra["coroutinesVersion"])
+ testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:" + rootProject.extra["coroutinesVersion"])
// Material
implementation("com.google.android.material:material:1.11.0")
@@ -148,6 +155,8 @@ dependencies {
// https://github.com/InsertKoinIO/koin
implementation("io.insert-koin:koin-core:" + rootProject.extra["koinVersion"])
implementation("io.insert-koin:koin-android:" + rootProject.extra["koinVersion"])
+ testImplementation("io.insert-koin:koin-test:" + rootProject.extra["koinVersion"])
+ testImplementation("io.insert-koin:koin-test-junit5:" + rootProject.extra["koinVersion"])
// Moxy MVP
// https://github.com/moxy-community/Moxy
@@ -191,4 +200,16 @@ dependencies {
// FlexboxLayoutManager
// https://github.com/google/flexbox-layout
implementation("com.google.android.flexbox:flexbox:3.0.0")
+
+ // Testing
+ // https://github.com/junit-team/junit5/
+ testImplementation("org.junit.jupiter:junit-jupiter:" + rootProject.extra["junitVersion"])
+
+ // Mocks for testing
+ // https://github.com/mockito/mockito
+ val mockitoVersion = "5.9.0"
+ testImplementation("org.mockito:mockito-core:$mockitoVersion")
+ testImplementation("org.mockito:mockito-junit-jupiter:$mockitoVersion")
+ // https://github.com/mockito/mockito-kotlin
+ testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 970de771..11338254 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -66,7 +66,7 @@
android:resource="@drawable/ic_notification"/>
+ android:resource="@color/globalColorAccent"/>
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/Screens.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/Screens.kt
index 80355f65..4098290e 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/Screens.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/Screens.kt
@@ -45,9 +45,9 @@ import ru.rznnike.eyehealthmanager.app.ui.fragment.settings.testing.TestingSetti
import ru.rznnike.eyehealthmanager.app.ui.fragment.splash.SplashFlowFragment
import ru.rznnike.eyehealthmanager.app.ui.fragment.splash.SplashFragment
import ru.rznnike.eyehealthmanager.domain.model.AcuityTestResult
-import ru.rznnike.eyehealthmanager.domain.model.AnalysisParameters
import ru.rznnike.eyehealthmanager.domain.model.AnalysisResult
import ru.rznnike.eyehealthmanager.domain.model.enums.AstigmatismAnswerType
+import ru.rznnike.eyehealthmanager.domain.model.enums.DaltonismAnomalyType
import ru.rznnike.eyehealthmanager.domain.model.enums.DayPart
import ru.rznnike.eyehealthmanager.domain.model.enums.NearFarAnswerType
@@ -119,7 +119,7 @@ object Screens {
fun daltonismResult(
errorsCount: Int,
- resultType: String
+ resultType: DaltonismAnomalyType
) = DaltonismResultFragment::class.getFragmentScreen(
DaltonismResultFragment.ERRORS_COUNT to errorsCount,
DaltonismResultFragment.RESULT_TYPE to resultType
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/AppModule.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/AppModule.kt
index e048c598..69b1b2dd 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/AppModule.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/AppModule.kt
@@ -15,6 +15,7 @@ import ru.rznnike.eyehealthmanager.app.observer.AppLifeCycleObserver
import ru.rznnike.eyehealthmanager.device.notification.Notificator
import ru.rznnike.eyehealthmanager.domain.global.CoroutineProvider
import ru.rznnike.eyehealthmanager.domain.global.DispatcherProvider
+import java.time.Clock
val appModule = module {
factory { androidContext().resources }
@@ -22,10 +23,11 @@ val appModule = module {
factory { AppLifeCycleObserver() }
single { Notifier(get()) }
single { ErrorHandler(get(), get()) }
- single { EventDispatcher() }
+ single { EventDispatcher(get()) }
single { ExternalIntentDispatcher(get()) }
single { Notificator(androidContext()) }
single { CrashlyticsProviderImpl() }
+ single { Clock.systemUTC() }
single {
object : CoroutineProvider {
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/DatabaseModule.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/DatabaseModule.kt
index a6ad8343..03c0ca79 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/DatabaseModule.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/DatabaseModule.kt
@@ -2,11 +2,25 @@ package ru.rznnike.eyehealthmanager.app.di
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module
+import ru.rznnike.eyehealthmanager.data.storage.dao.AcuityTestDAO
+import ru.rznnike.eyehealthmanager.data.storage.dao.AstigmatismTestDAO
+import ru.rznnike.eyehealthmanager.data.storage.dao.ColorPerceptionTestDAO
+import ru.rznnike.eyehealthmanager.data.storage.dao.ContrastTestDAO
+import ru.rznnike.eyehealthmanager.data.storage.dao.DaltonismTestDAO
+import ru.rznnike.eyehealthmanager.data.storage.dao.NearFarTestDAO
+import ru.rznnike.eyehealthmanager.data.storage.dao.TestDAO
import ru.rznnike.eyehealthmanager.data.storage.entity.MyObjectBox
import ru.rznnike.eyehealthmanager.domain.storage.repository.TestRepository
import ru.rznnike.eyehealthmanager.data.storage.repository.TestRepositoryImpl
val databaseModule = module {
single { MyObjectBox.builder().androidContext(androidContext()).build() }
- single { TestRepositoryImpl(get()) }
+ single { TestDAO(get()) }
+ single { AcuityTestDAO(get()) }
+ single { AstigmatismTestDAO(get()) }
+ single { ColorPerceptionTestDAO(get()) }
+ single { ContrastTestDAO(get()) }
+ single { DaltonismTestDAO(get()) }
+ single { NearFarTestDAO(get()) }
+ single { TestRepositoryImpl(get(), get(), get(), get(), get(), get(), get(), get()) }
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/GatewayModule.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/GatewayModule.kt
index 338b5ef2..13b7162a 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/GatewayModule.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/GatewayModule.kt
@@ -15,7 +15,7 @@ import ru.rznnike.eyehealthmanager.domain.gateway.UserGateway
val gatewayModule = module {
single { UserGatewayImpl(get()) }
single { NotificationGatewayImpl() }
- single { TestGatewayImpl(get(), get()) }
- single { AnalysisGatewayImpl(get()) }
- single { DevGatewayImpl(get()) }
+ single { TestGatewayImpl(get(), get(), get()) }
+ single { AnalysisGatewayImpl(get(), get()) }
+ single { DevGatewayImpl(get(), get()) }
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/InteractorModule.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/InteractorModule.kt
index 79e26754..8394e3cc 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/InteractorModule.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/di/InteractorModule.kt
@@ -8,6 +8,7 @@ import ru.rznnike.eyehealthmanager.domain.interactor.notification.ObserveCancelN
import ru.rznnike.eyehealthmanager.domain.interactor.notification.ObserveShowNotificationUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.test.*
import ru.rznnike.eyehealthmanager.domain.interactor.user.GetAcuityTestingSettingsUseCase
+import ru.rznnike.eyehealthmanager.domain.interactor.user.GetAppThemeUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.user.GetApplyDynamicCorrectionsUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.user.SetUserLanguageUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.user.GetDisplayedChangelogVersionUseCase
@@ -15,6 +16,7 @@ import ru.rznnike.eyehealthmanager.domain.interactor.user.GetTestingSettingsUseC
import ru.rznnike.eyehealthmanager.domain.interactor.user.GetUserLanguageUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.user.GetWelcomeDialogShowedUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.user.SetAcuityTestingSettingsUseCase
+import ru.rznnike.eyehealthmanager.domain.interactor.user.SetAppThemeUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.user.SetApplyDynamicCorrectionsUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.user.SetDisplayedChangelogVersionUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.user.SetTestingSettingsUseCase
@@ -33,6 +35,8 @@ val interactorModule = module {
single { SetAcuityTestingSettingsUseCase(get(), get()) }
single { GetApplyDynamicCorrectionsUseCase(get(), get()) }
single { SetApplyDynamicCorrectionsUseCase(get(), get()) }
+ single { GetAppThemeUseCase(get(), get()) }
+ single { SetAppThemeUseCase(get(), get()) }
single { GetTestResultsUseCase(get(), get()) }
single { AddTestResultUseCase(get(), get()) }
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/dialog/DialogUtils.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/dialog/DialogUtils.kt
index df1a2211..a0d3df3a 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/dialog/DialogUtils.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/dialog/DialogUtils.kt
@@ -4,7 +4,11 @@ import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.content.Context
import android.os.Build
-import android.view.*
+import android.view.Gravity
+import android.view.View
+import android.view.Window
+import android.view.WindowInsetsController
+import android.view.WindowManager
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
@@ -29,8 +33,12 @@ import ru.rznnike.eyehealthmanager.app.dialog.bottom.BottomDialogParameters
import ru.rznnike.eyehealthmanager.app.ui.view.EmptyDividerDecoration
import ru.rznnike.eyehealthmanager.app.utils.extensions.addSystemWindowInsetToPadding
import ru.rznnike.eyehealthmanager.app.utils.extensions.deviceSize
+import ru.rznnike.eyehealthmanager.app.utils.extensions.isNightModeEnabled
import ru.rznnike.eyehealthmanager.app.utils.extensions.toHtmlSpanned
-import java.util.*
+import ru.rznnike.eyehealthmanager.domain.utils.currentTimeMillis
+import ru.rznnike.eyehealthmanager.domain.utils.millis
+import ru.rznnike.eyehealthmanager.domain.utils.toDateTime
+import ru.rznnike.eyehealthmanager.domain.utils.toLocalDate
fun Context.showAlertDialog(
parameters: AlertDialogParameters,
@@ -222,43 +230,37 @@ fun Context.showDatePicker(
onCancel: (() -> Unit)? = null,
onSuccess: (date: Long) -> Unit
) {
- val currentCalendar = Calendar.getInstance().apply {
- timeInMillis = preselectedDate ?: System.currentTimeMillis()
- }
+ val currentDate = (preselectedDate ?: currentTimeMillis()).toLocalDate()
DatePickerDialog(
this,
- android.R.style.ThemeOverlay_Material_Dialog,
+ R.style.AppTheme_Dialog_DatePicker,
{ _, year, month, dayOfMonth ->
if (enableTimePicker) {
showTimePicker(
preselectedTime = preselectedDate,
onCancel = onCancel,
- onSuccess = { time ->
- val selectedTime = Calendar.getInstance().apply {
- timeInMillis = time
- set(Calendar.YEAR, year)
- set(Calendar.MONTH, month)
- set(Calendar.DAY_OF_MONTH, dayOfMonth)
- }.timeInMillis
+ onSuccess = { timestamp ->
+ val selectedTime = timestamp.toDateTime()
+ .withYear(year)
+ .withMonth(month + 1)
+ .withDayOfMonth(dayOfMonth)
+ .millis()
onSuccess(selectedTime)
}
)
} else {
- val selectedTime = Calendar.getInstance().apply {
- set(Calendar.YEAR, year)
- set(Calendar.MONTH, month)
- set(Calendar.DAY_OF_MONTH, dayOfMonth)
- set(Calendar.HOUR_OF_DAY, 0)
- set(Calendar.MINUTE, 0)
- set(Calendar.SECOND, 0)
- set(Calendar.MILLISECOND, 0)
- }.timeInMillis
+ val selectedTime = currentTimeMillis().toDateTime().toLocalDate()
+ .withYear(year)
+ .withMonth(month + 1)
+ .withDayOfMonth(dayOfMonth)
+ .atStartOfDay()
+ .millis()
onSuccess(selectedTime)
}
},
- currentCalendar.get(Calendar.YEAR),
- currentCalendar.get(Calendar.MONTH),
- currentCalendar.get(Calendar.DAY_OF_MONTH)
+ currentDate.year,
+ currentDate.monthValue - 1,
+ currentDate.dayOfMonth
).apply {
maxDate?.let { datePicker.maxDate = it }
minDate?.let { datePicker.minDate = it }
@@ -270,25 +272,23 @@ fun Context.showDatePicker(
fun Context.showTimePicker(
preselectedTime: Long? = null,
onCancel: (() -> Unit)? = null,
- onSuccess: (date: Long) -> Unit
+ onSuccess: (timestamp: Long) -> Unit
) {
- val currentCalendar = Calendar.getInstance().apply {
- timeInMillis = preselectedTime ?: System.currentTimeMillis()
- }
+ val currentDate = (preselectedTime ?: currentTimeMillis()).toDateTime()
TimePickerDialog(
this,
- android.R.style.ThemeOverlay_Material_Dialog,
+ R.style.AppTheme_Dialog_DatePicker,
{ _, hourOfDay, minute ->
- val selectedTime = Calendar.getInstance().apply {
- set(Calendar.HOUR_OF_DAY, hourOfDay)
- set(Calendar.MINUTE, minute)
- set(Calendar.SECOND, 0)
- set(Calendar.MILLISECOND, 0)
- }.timeInMillis
+ val selectedTime = currentTimeMillis().toDateTime()
+ .withHour(hourOfDay)
+ .withMinute(minute)
+ .withSecond(0)
+ .withNano(0)
+ .millis()
onSuccess(selectedTime)
},
- currentCalendar.get(Calendar.HOUR_OF_DAY),
- currentCalendar.get(Calendar.MINUTE),
+ currentDate.hour,
+ currentDate.minute,
true
).apply {
setOnCancelListener { onCancel?.invoke() }
@@ -365,6 +365,7 @@ fun Fragment.showCustomBottomDialog(
}
private fun Window.setLightNavigationBar() = when {
+ context.isNightModeEnabled -> Unit // disable for dark theme
Build.VERSION.SDK_INT >= 30 -> {
insetsController?.setSystemBarsAppearance(
WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS,
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/event/EventDispatcher.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/event/EventDispatcher.kt
index 782c5c2f..bb7e0510 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/event/EventDispatcher.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/event/EventDispatcher.kt
@@ -1,12 +1,13 @@
package ru.rznnike.eyehealthmanager.app.dispatcher.event
-import android.os.Handler
-import android.os.Looper
+import kotlinx.coroutines.launch
+import ru.rznnike.eyehealthmanager.domain.global.CoroutineProvider
import java.util.*
-import kotlin.collections.ArrayList
import kotlin.reflect.KClass
-class EventDispatcher {
+class EventDispatcher(
+ private val coroutineProvider: CoroutineProvider
+) {
private val eventListeners = HashMap>()
fun addEventListener(appEventClass: KClass, listener: EventListener): EventListener {
@@ -44,10 +45,8 @@ class EventDispatcher {
.filter { it.key == key && it.value.size > 0 }
.forEach {
it.value.forEach { listener ->
- Handler(Looper.getMainLooper()).post {
- listener.onEvent(
- appEvent
- )
+ coroutineProvider.scopeMain.launch {
+ listener.onEvent(appEvent)
}
}
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/external/ExternalIntentDispatcher.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/external/ExternalIntentDispatcher.kt
index 6b835fba..fd79aef3 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/external/ExternalIntentDispatcher.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/external/ExternalIntentDispatcher.kt
@@ -1,6 +1,5 @@
package ru.rznnike.eyehealthmanager.app.dispatcher.external
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
@@ -14,9 +13,7 @@ class ExternalIntentDispatcher(
ExternalIntentData.App().apply { processed = true }
)
- fun subscribe(): Flow {
- return eventsFlow.asStateFlow()
- }
+ fun subscribe() = eventsFlow.asStateFlow()
fun send(data: ExternalIntentData) {
coroutineProvider.scopeIo.launch {
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/notifier/Notifier.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/notifier/Notifier.kt
index 49a495eb..2891cd1b 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/notifier/Notifier.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/dispatcher/notifier/Notifier.kt
@@ -17,89 +17,77 @@ class Notifier(
text: String,
level: SystemMessage.Level = SystemMessage.Level.NORMAL,
showOnTop: Boolean = false
- ) {
- val msg = SystemMessage(
+ ) = emitMessage(
+ SystemMessage(
text = text,
type = SystemMessage.Type.BAR,
showOnTop = showOnTop,
level = level
)
- coroutineProvider.scopeIo.launch {
- notifierFlow.emit(msg)
- }
- }
+ )
fun sendMessage(
@StringRes textRes: Int,
level: SystemMessage.Level = SystemMessage.Level.NORMAL,
showOnTop: Boolean = false
- ) {
- val msg = SystemMessage(
+ ) = emitMessage(
+ SystemMessage(
textRes = textRes,
type = SystemMessage.Type.BAR,
showOnTop = showOnTop,
level = level
)
- coroutineProvider.scopeIo.launch {
- notifierFlow.emit(msg)
- }
- }
+ )
- fun sendAlert(text: String) {
- val msg = SystemMessage(
+ fun sendAlert(text: String) = emitMessage(
+ SystemMessage(
text = text,
type = SystemMessage.Type.ALERT,
showOnTop = false
)
- coroutineProvider.scopeIo.launch {
- notifierFlow.emit(msg)
- }
- }
+ )
- fun sendAlert(@StringRes textRes: Int) {
- val msg = SystemMessage(
+ fun sendAlert(@StringRes textRes: Int) = emitMessage(
+ SystemMessage(
textRes = textRes,
type = SystemMessage.Type.ALERT,
showOnTop = false
)
- coroutineProvider.scopeIo.launch {
- notifierFlow.emit(msg)
- }
- }
+ )
fun sendActionMessage(
@StringRes textRes: Int,
@StringRes actionTextRes: Int,
showOnTop: Boolean = false,
actionCallback: () -> Unit
- ) {
- val msg = SystemMessage(
+ ) = emitMessage(
+ SystemMessage(
textRes = textRes,
actionTextRes = actionTextRes,
actionCallback = actionCallback,
type = SystemMessage.Type.BAR,
showOnTop = showOnTop
)
- coroutineProvider.scopeIo.launch {
- notifierFlow.emit(msg)
- }
- }
+ )
fun sendActionMessage(
text: String,
actionText: String,
showOnTop: Boolean = false,
actionCallback: () -> Unit
- ) {
- val msg = SystemMessage(
+ ) = emitMessage(
+ SystemMessage(
text = text,
actionText = actionText,
actionCallback = actionCallback,
type = SystemMessage.Type.BAR,
showOnTop = showOnTop
)
+ )
+
+ private fun emitMessage(message: SystemMessage) {
coroutineProvider.scopeIo.launch {
- notifierFlow.emit(msg)
+ notifierFlow.emit(message)
}
}
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/global/ui/activity/BaseActivity.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/global/ui/activity/BaseActivity.kt
index 5482a0ca..8f356983 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/global/ui/activity/BaseActivity.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/global/ui/activity/BaseActivity.kt
@@ -11,7 +11,9 @@ import org.koin.android.ext.android.inject
import ru.rznnike.eyehealthmanager.R
import ru.rznnike.eyehealthmanager.app.global.presentation.ErrorHandler
import ru.rznnike.eyehealthmanager.app.global.ui.fragment.BaseFragment
+import ru.rznnike.eyehealthmanager.app.utils.extensions.applyTheme
import ru.rznnike.eyehealthmanager.data.preference.PreferencesWrapper
+import ru.rznnike.eyehealthmanager.domain.model.enums.AppTheme
import ru.rznnike.eyehealthmanager.domain.model.enums.Language
abstract class BaseActivity(@LayoutRes layoutRes: Int) : MvpAppCompatActivity(layoutRes) {
@@ -23,6 +25,7 @@ abstract class BaseActivity(@LayoutRes layoutRes: Int) : MvpAppCompatActivity(la
override fun onCreate(savedInstanceState: Bundle?) {
setLanguage()
+ applyTheme(AppTheme[preferences.appTheme.get()])
onBackPressedDispatcher.addCallback(this) {
currentFragment?.onBackPressed()
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/global/ui/fragment/BaseFragment.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/global/ui/fragment/BaseFragment.kt
index a054827a..447aa087 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/global/ui/fragment/BaseFragment.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/global/ui/fragment/BaseFragment.kt
@@ -10,13 +10,16 @@ import moxy.MvpAppCompatFragment
import org.koin.androidx.viewmodel.ext.android.getViewModel
import ru.rznnike.eyehealthmanager.app.navigation.FlowNavigationViewModel
import ru.rznnike.eyehealthmanager.app.utils.extensions.hideKeyboard
+import ru.rznnike.eyehealthmanager.app.utils.extensions.isNightModeEnabled
import java.util.*
import kotlin.concurrent.schedule
abstract class BaseFragment(@LayoutRes layoutRes: Int) : MvpAppCompatFragment(layoutRes) {
open var isLightStatusBar: Boolean = true
+ get() = !(context?.isNightModeEnabled ?: false)
protected set
open var isLightNavigationBar: Boolean = true
+ get() = !(context?.isNightModeEnabled ?: false)
protected set
open var progressDelayMs: Long = DEFAULT_PROGRESS_DELAY_MS
protected set
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/navigation/FragmentScreenWithArguments.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/navigation/FragmentScreenWithArguments.kt
new file mode 100644
index 00000000..473b0254
--- /dev/null
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/navigation/FragmentScreenWithArguments.kt
@@ -0,0 +1,15 @@
+package ru.rznnike.eyehealthmanager.app.navigation
+
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentFactory
+import com.github.terrakok.cicerone.androidx.Creator
+import com.github.terrakok.cicerone.androidx.FragmentScreen
+
+class FragmentScreenWithArguments(
+ val arguments: Map,
+ val fragmentCreator: Creator,
+ override val screenKey: String,
+ override val clearContainer: Boolean = true
+) : FragmentScreen {
+ override fun createFragment(factory: FragmentFactory) = fragmentCreator.create(factory)
+}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/navigation/NavigationUtils.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/navigation/NavigationUtils.kt
index e2ce2d76..3ddf3cd4 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/navigation/NavigationUtils.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/navigation/NavigationUtils.kt
@@ -2,9 +2,12 @@ package ru.rznnike.eyehealthmanager.app.navigation
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
-import com.github.terrakok.cicerone.*
+import com.github.terrakok.cicerone.BackTo
+import com.github.terrakok.cicerone.Command
+import com.github.terrakok.cicerone.Forward
+import com.github.terrakok.cicerone.Navigator
+import com.github.terrakok.cicerone.Replace
import com.github.terrakok.cicerone.Screen
-import com.github.terrakok.cicerone.androidx.FragmentScreen
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance
@@ -24,13 +27,14 @@ fun Navigator.setLaunchScreenChain(vararg screens: Screen) {
}
fun KClass.getFragmentScreen(
- vararg args: Pair,
+ vararg arguments: Pair,
clearContainer: Boolean = true
-) = FragmentScreen(
- key = java.name,
+) = FragmentScreenWithArguments(
+ arguments = arguments.toMap(),
+ screenKey = java.name,
fragmentCreator = {
- this.createInstance().apply {
- arguments = bundleOf(*args)
+ createInstance().apply {
+ this.arguments = bundleOf(*arguments)
}
},
clearContainer = clearContainer
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/observer/AppLifecycleObserver.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/observer/AppLifeCycleObserver.kt
similarity index 100%
rename from app/src/main/java/ru/rznnike/eyehealthmanager/app/observer/AppLifecycleObserver.kt
rename to app/src/main/java/ru/rznnike/eyehealthmanager/app/observer/AppLifeCycleObserver.kt
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/pagination/Paginator.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/pagination/Paginator.kt
index a34ea9f9..a2043919 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/pagination/Paginator.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/pagination/Paginator.kt
@@ -34,7 +34,7 @@ class Paginator(
fun refresh(forceRefresh: Boolean = false) {
if (forceRefresh || (state != State.LOADING)) {
load(
- limit = if (data.isEmpty()) limit else data.size.coerceAtLeast(DEFAULT_PAGE_LIMIT),
+ limit = if (data.isEmpty()) limit else data.size.coerceAtLeast(limit),
isRefresh = true
)
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/doctor/AcuityDoctorResultPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/doctor/AcuityDoctorResultPresenter.kt
index ea83899a..83f14a81 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/doctor/AcuityDoctorResultPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/doctor/AcuityDoctorResultPresenter.kt
@@ -16,9 +16,11 @@ import ru.rznnike.eyehealthmanager.domain.model.enums.AcuityTestSymbolsType
import ru.rznnike.eyehealthmanager.domain.model.enums.DayPart
import ru.rznnike.eyehealthmanager.domain.model.enums.TestEyesType
import ru.rznnike.eyehealthmanager.domain.utils.toFloatOrNullSmart
+import java.time.Clock
@InjectViewState
class AcuityDoctorResultPresenter : BasePresenter() {
+ private val clock: Clock by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
private val eventDispatcher: EventDispatcher by inject()
@@ -61,7 +63,7 @@ class AcuityDoctorResultPresenter : BasePresenter() {
else -> {
viewState.setProgress(true)
val testResult = AcuityTestResult(
- timestamp = date ?: System.currentTimeMillis(),
+ timestamp = date ?: clock.millis(),
symbolsType = AcuityTestSymbolsType.LETTERS_RU,
testEyesType = when {
leftEyeFloat == null -> TestEyesType.RIGHT
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/info/AcuityInfoPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/info/AcuityInfoPresenter.kt
index a73bf854..a793c73d 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/info/AcuityInfoPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/info/AcuityInfoPresenter.kt
@@ -17,9 +17,11 @@ import ru.rznnike.eyehealthmanager.domain.model.enums.AcuityTestSymbolsType
import ru.rznnike.eyehealthmanager.domain.model.enums.DayPart
import ru.rznnike.eyehealthmanager.domain.model.enums.TestEyesType
import ru.rznnike.eyehealthmanager.domain.utils.getDayTime
+import java.time.Clock
@InjectViewState
class AcuityInfoPresenter : BasePresenter(), EventDispatcher.EventListener {
+ private val clock: Clock by inject()
private val eventDispatcher: EventDispatcher by inject()
private val getTestingSettingsUseCase: GetTestingSettingsUseCase by inject()
private val getAcuityTestingSettingsUseCase: GetAcuityTestingSettingsUseCase by inject()
@@ -93,7 +95,7 @@ class AcuityInfoPresenter : BasePresenter(), EventDispatcher.Eve
}
private fun autoSelectDayPart() =
- when (val currentDayTime = System.currentTimeMillis().getDayTime()) {
+ when (val currentDayTime = clock.millis().getDayTime()) {
generalSettings.timeToDayBeginning -> DayPart.BEGINNING
generalSettings.timeToDayMiddle -> DayPart.MIDDLE
generalSettings.timeToDayEnd -> DayPart.END
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/result/AcuityResultPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/result/AcuityResultPresenter.kt
index 0242cf7d..537c5eed 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/result/AcuityResultPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/result/AcuityResultPresenter.kt
@@ -19,13 +19,15 @@ import ru.rznnike.eyehealthmanager.domain.model.AnalysisResult
import ru.rznnike.eyehealthmanager.domain.model.enums.AnalysisType
import ru.rznnike.eyehealthmanager.domain.model.exception.NotEnoughDataException
import ru.rznnike.eyehealthmanager.domain.utils.atEndOfDay
-import ru.rznnike.eyehealthmanager.domain.utils.getTodayCalendar
-import java.util.Calendar
+import ru.rznnike.eyehealthmanager.domain.utils.millis
+import ru.rznnike.eyehealthmanager.domain.utils.toLocalDate
+import java.time.Clock
@InjectViewState
class AcuityResultPresenter(
private val testResult: AcuityTestResult
) : BasePresenter() {
+ private val clock: Clock by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
private val eventDispatcher: EventDispatcher by inject()
@@ -40,11 +42,10 @@ class AcuityResultPresenter(
presenterScope.launch {
viewState.setProgress(true)
applyDynamicCorrections = getApplyDynamicCorrectionsUseCase().data ?: false
+ val dateNow = clock.millis().toLocalDate()
val parameters = AnalysisParameters(
- dateFrom = getTodayCalendar().apply {
- add(Calendar.MONTH, -1)
- }.timeInMillis,
- dateTo = Calendar.getInstance().atEndOfDay().timeInMillis,
+ dateFrom = dateNow.minusMonths(1).atStartOfDay().millis(),
+ dateTo = dateNow.atEndOfDay().millis(),
applyDynamicCorrections = applyDynamicCorrections,
analysisType = AnalysisType.ACUITY_ONLY
)
@@ -57,8 +58,8 @@ class AcuityResultPresenter(
if (error !is NotEnoughDataException) {
notifier.sendMessage(it)
}
- populateData()
}
+ populateData()
}
)
viewState.setProgress(false)
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/test/AcuityTestPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/test/AcuityTestPresenter.kt
index 9490e8b0..c99ffbc5 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/test/AcuityTestPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/acuity/test/AcuityTestPresenter.kt
@@ -15,6 +15,7 @@ import ru.rznnike.eyehealthmanager.domain.interactor.user.GetAcuityTestingSettin
import ru.rznnike.eyehealthmanager.domain.interactor.user.GetTestingSettingsUseCase
import ru.rznnike.eyehealthmanager.domain.model.*
import ru.rznnike.eyehealthmanager.domain.model.enums.*
+import java.time.Clock
import kotlin.math.pow
import kotlin.math.sqrt
@@ -28,6 +29,7 @@ private const val MAX_ANSWERS = 3
class AcuityTestPresenter(
private var dayPart: DayPart
) : BasePresenter() {
+ private val clock: Clock by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
private val eventDispatcher: EventDispatcher by inject()
@@ -145,7 +147,7 @@ class AcuityTestPresenter(
} else {
viewState.setProgress(true)
val testResult = AcuityTestResult(
- timestamp = System.currentTimeMillis(),
+ timestamp = clock.millis(),
symbolsType = acuitySettings.symbolsType,
testEyesType = acuitySettings.eyesType,
dayPart = dayPart,
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/analysis/parameters/AnalysisParametersPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/analysis/parameters/AnalysisParametersPresenter.kt
index dfdd5119..7235e480 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/analysis/parameters/AnalysisParametersPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/analysis/parameters/AnalysisParametersPresenter.kt
@@ -16,15 +16,14 @@ import ru.rznnike.eyehealthmanager.domain.model.enums.AnalysisType
import ru.rznnike.eyehealthmanager.domain.model.exception.NotEnoughDataException
import ru.rznnike.eyehealthmanager.domain.utils.GlobalConstants
import ru.rznnike.eyehealthmanager.domain.utils.atEndOfDay
-import ru.rznnike.eyehealthmanager.domain.utils.atStartOfDay
-import ru.rznnike.eyehealthmanager.domain.utils.getTodayCalendar
-import ru.rznnike.eyehealthmanager.domain.utils.toCalendar
+import ru.rznnike.eyehealthmanager.domain.utils.millis
import ru.rznnike.eyehealthmanager.domain.utils.toLocalDate
+import java.time.Clock
import java.time.temporal.ChronoUnit
-import java.util.*
@InjectViewState
class AnalysisParametersPresenter : BasePresenter() {
+ private val clock: Clock by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
private val getApplyDynamicCorrectionsUseCase: GetApplyDynamicCorrectionsUseCase by inject()
@@ -39,11 +38,10 @@ class AnalysisParametersPresenter : BasePresenter() {
private fun initData() {
presenterScope.launch {
+ val dateNow = clock.millis().toLocalDate()
parameters.apply {
- dateFrom = getTodayCalendar().apply {
- add(Calendar.DAY_OF_MONTH, -GlobalConstants.ANALYSIS_MAX_RANGE_DAYS)
- }.timeInMillis
- dateTo = Calendar.getInstance().atEndOfDay().timeInMillis
+ dateFrom = dateNow.minusDays(GlobalConstants.ANALYSIS_MAX_RANGE_DAYS - 1).atStartOfDay().millis()
+ dateTo = dateNow.atEndOfDay().millis()
applyDynamicCorrections = getApplyDynamicCorrectionsUseCase().data ?: false
}
viewState.populateData(parameters)
@@ -51,48 +49,40 @@ class AnalysisParametersPresenter : BasePresenter() {
}
fun onDateFromValueChanged(newValue: Long) {
- parameters.dateFrom = newValue.toCalendar().atStartOfDay().timeInMillis
+ parameters.dateFrom = newValue.toLocalDate().atStartOfDay().millis()
val deltaDays = ChronoUnit.DAYS.between(parameters.dateFrom.toLocalDate(), parameters.dateTo.toLocalDate())
when {
- deltaDays < GlobalConstants.ANALYSIS_MIN_RANGE_DAYS -> {
- parameters.dateTo = newValue.toCalendar()
- .apply {
- add(Calendar.DAY_OF_MONTH, GlobalConstants.ANALYSIS_MIN_RANGE_DAYS)
- }
+ deltaDays < (GlobalConstants.ANALYSIS_MIN_RANGE_DAYS - 1) -> {
+ parameters.dateTo = newValue.toLocalDate()
+ .plusDays(GlobalConstants.ANALYSIS_MIN_RANGE_DAYS - 1)
.atEndOfDay()
- .timeInMillis
+ .millis()
}
- deltaDays > GlobalConstants.ANALYSIS_MAX_RANGE_DAYS -> {
- parameters.dateTo = newValue.toCalendar()
- .apply {
- add(Calendar.DAY_OF_MONTH, GlobalConstants.ANALYSIS_MAX_RANGE_DAYS)
- }
+ deltaDays > (GlobalConstants.ANALYSIS_MAX_RANGE_DAYS - 1) -> {
+ parameters.dateTo = newValue.toLocalDate()
+ .plusDays(GlobalConstants.ANALYSIS_MAX_RANGE_DAYS - 1)
.atEndOfDay()
- .timeInMillis
+ .millis()
}
}
viewState.populateData(parameters)
}
fun onDateToValueChanged(newValue: Long) {
- parameters.dateTo = newValue.toCalendar().atEndOfDay().timeInMillis
+ parameters.dateTo = newValue.toLocalDate().atEndOfDay().millis()
val deltaDays = ChronoUnit.DAYS.between(parameters.dateFrom.toLocalDate(), parameters.dateTo.toLocalDate())
when {
- deltaDays < GlobalConstants.ANALYSIS_MIN_RANGE_DAYS -> {
- parameters.dateFrom = newValue.toCalendar()
- .apply {
- add(Calendar.DAY_OF_MONTH, -GlobalConstants.ANALYSIS_MIN_RANGE_DAYS)
- }
+ deltaDays < (GlobalConstants.ANALYSIS_MIN_RANGE_DAYS - 1) -> {
+ parameters.dateFrom = newValue.toLocalDate()
+ .minusDays(GlobalConstants.ANALYSIS_MIN_RANGE_DAYS - 1)
.atStartOfDay()
- .timeInMillis
+ .millis()
}
- deltaDays > GlobalConstants.ANALYSIS_MAX_RANGE_DAYS -> {
- parameters.dateFrom = newValue.toCalendar()
- .apply {
- add(Calendar.DAY_OF_MONTH, -GlobalConstants.ANALYSIS_MAX_RANGE_DAYS)
- }
+ deltaDays > (GlobalConstants.ANALYSIS_MAX_RANGE_DAYS - 1) -> {
+ parameters.dateFrom = newValue.toLocalDate()
+ .minusDays(GlobalConstants.ANALYSIS_MAX_RANGE_DAYS - 1)
.atStartOfDay()
- .timeInMillis
+ .millis()
}
}
viewState.populateData(parameters)
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/analysis/result/AnalysisResultView.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/analysis/result/AnalysisResultView.kt
index d35c710d..3bc949c6 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/analysis/result/AnalysisResultView.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/analysis/result/AnalysisResultView.kt
@@ -1,7 +1,6 @@
package ru.rznnike.eyehealthmanager.app.presentation.analysis.result
import moxy.viewstate.strategy.alias.AddToEndSingle
-import moxy.viewstate.strategy.alias.OneExecution
import ru.rznnike.eyehealthmanager.app.global.presentation.NavigationMvpView
import ru.rznnike.eyehealthmanager.domain.model.AnalysisResult
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/astigmatism/answer/AstigmatismAnswerPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/astigmatism/answer/AstigmatismAnswerPresenter.kt
index 6dc580ff..4d184e55 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/astigmatism/answer/AstigmatismAnswerPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/astigmatism/answer/AstigmatismAnswerPresenter.kt
@@ -13,9 +13,11 @@ import ru.rznnike.eyehealthmanager.app.global.presentation.ErrorHandler
import ru.rznnike.eyehealthmanager.domain.interactor.test.AddTestResultUseCase
import ru.rznnike.eyehealthmanager.domain.model.AstigmatismTestResult
import ru.rznnike.eyehealthmanager.domain.model.enums.AstigmatismAnswerType
+import java.time.Clock
@InjectViewState
class AstigmatismAnswerPresenter : BasePresenter() {
+ private val clock: Clock by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
private val eventDispatcher: EventDispatcher by inject()
@@ -28,7 +30,7 @@ class AstigmatismAnswerPresenter : BasePresenter() {
val typeRightEye = if (answerRightEye == 0) AstigmatismAnswerType.OK else AstigmatismAnswerType.ANOMALY
val testResult = AstigmatismTestResult(
- timestamp = System.currentTimeMillis(),
+ timestamp = clock.millis(),
resultLeftEye = typeLeftEye,
resultRightEye = typeRightEye
)
@@ -42,6 +44,7 @@ class AstigmatismAnswerPresenter : BasePresenter() {
}
)
eventDispatcher.sendEvent(AppEvent.JournalChanged)
+ viewState.setProgress(false)
}
}
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/colorperception/test/ColorPerceptionTestPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/colorperception/test/ColorPerceptionTestPresenter.kt
index 118969a4..5fade5c3 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/colorperception/test/ColorPerceptionTestPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/colorperception/test/ColorPerceptionTestPresenter.kt
@@ -13,9 +13,11 @@ import ru.rznnike.eyehealthmanager.app.global.presentation.ErrorHandler
import ru.rznnike.eyehealthmanager.domain.interactor.test.AddTestResultUseCase
import ru.rznnike.eyehealthmanager.domain.model.ColorPerceptionTestData
import ru.rznnike.eyehealthmanager.domain.model.ColorPerceptionTestResult
+import java.time.Clock
@InjectViewState
class ColorPerceptionTestPresenter : BasePresenter() {
+ private val clock: Clock by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
private val eventDispatcher: EventDispatcher by inject()
@@ -57,7 +59,7 @@ class ColorPerceptionTestPresenter : BasePresenter() {
presenterScope.launch {
viewState.setProgress(true)
val testResult = ColorPerceptionTestResult(
- timestamp = System.currentTimeMillis(),
+ timestamp = clock.millis(),
recognizedColorsCount = recognizedColorsCount,
allColorsCount = ColorPerceptionTestData.colors.size
)
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/contrast/test/ContrastTestPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/contrast/test/ContrastTestPresenter.kt
index 0e833a57..6e913f12 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/contrast/test/ContrastTestPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/contrast/test/ContrastTestPresenter.kt
@@ -13,6 +13,7 @@ import ru.rznnike.eyehealthmanager.app.global.presentation.ErrorHandler
import ru.rznnike.eyehealthmanager.domain.interactor.test.AddTestResultUseCase
import ru.rznnike.eyehealthmanager.domain.model.ContrastTestResult
import ru.rznnike.eyehealthmanager.domain.model.enums.Direction
+import java.time.Clock
import kotlin.random.Random
private const val START_VALUE = 100
@@ -25,6 +26,7 @@ private const val MAX_ANSWERS = 3
@InjectViewState
class ContrastTestPresenter : BasePresenter() {
+ private val clock: Clock by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
private val eventDispatcher: EventDispatcher by inject()
@@ -38,9 +40,9 @@ class ContrastTestPresenter : BasePresenter() {
private var maxBaseSteps = 0
private var currentBaseStep = 0
- init {
+ override fun onFirstViewAttach() {
initData()
- goToNextStep()
+ nextStep()
}
private fun initData() {
@@ -52,15 +54,15 @@ class ContrastTestPresenter : BasePresenter() {
}
}
- fun onAnswer(direction: Direction) {
+ fun answer(direction: Direction) {
answersCount++
if (direction == currentDirection) {
correctAnswersCount++
}
- goToNextStep()
+ nextStep()
}
- private fun goToNextStep() = when {
+ private fun nextStep() = when {
correctAnswersCount >= MIN_CORRECT_ANSWERS -> {
recognizedDelta = currentDelta
if (recognizedDelta <= END_VALUE) {
@@ -101,7 +103,7 @@ class ContrastTestPresenter : BasePresenter() {
presenterScope.launch {
viewState.setProgress(true)
val testResult = ContrastTestResult(
- timestamp = System.currentTimeMillis(),
+ timestamp = clock.millis(),
recognizedContrast = recognizedDelta
)
addTestResultUseCase(testResult).process(
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/daltonism/test/DaltonismTestPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/daltonism/test/DaltonismTestPresenter.kt
index 0ad6d8a5..7c76ba7a 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/daltonism/test/DaltonismTestPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/daltonism/test/DaltonismTestPresenter.kt
@@ -14,11 +14,13 @@ import ru.rznnike.eyehealthmanager.domain.interactor.test.AddTestResultUseCase
import ru.rznnike.eyehealthmanager.domain.model.DaltonismTestData
import ru.rznnike.eyehealthmanager.domain.model.DaltonismTestResult
import ru.rznnike.eyehealthmanager.domain.model.enums.DaltonismAnomalyType
+import java.time.Clock
private const val NORMAL_BORDER = 2
@InjectViewState
class DaltonismTestPresenter : BasePresenter() {
+ private val clock: Clock by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
private val eventDispatcher: EventDispatcher by inject()
@@ -29,11 +31,11 @@ class DaltonismTestPresenter : BasePresenter() {
private val userAnswers: MutableList = mutableListOf()
private val answerDeltas: MutableMap = mutableMapOf()
- init {
+ override fun onFirstViewAttach() {
nextStep()
}
- fun onAnswer(selection: Int) {
+ fun answer(selection: Int) {
userAnswers.add(answersOrder[selection])
nextStep()
}
@@ -89,7 +91,7 @@ class DaltonismTestPresenter : BasePresenter() {
}
val testResult = DaltonismTestResult(
- timestamp = System.currentTimeMillis(),
+ timestamp = clock.millis(),
errorsCount = errorsCount,
anomalyType = anomalyType
)
@@ -98,7 +100,7 @@ class DaltonismTestPresenter : BasePresenter() {
viewState.routerNewRootScreen(
Screens.Screen.daltonismResult(
errorsCount = errorsCount,
- resultType = anomalyType.toString()
+ resultType = anomalyType
)
)
}, { error ->
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/journal/backup/ExportJournalPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/journal/backup/ExportJournalPresenter.kt
index e33113ea..e9ae0911 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/journal/backup/ExportJournalPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/journal/backup/ExportJournalPresenter.kt
@@ -20,13 +20,13 @@ import ru.rznnike.eyehealthmanager.domain.model.TestResultFilter
import ru.rznnike.eyehealthmanager.domain.model.enums.TestType
import ru.rznnike.eyehealthmanager.domain.utils.GlobalConstants
import ru.rznnike.eyehealthmanager.domain.utils.atEndOfDay
-import ru.rznnike.eyehealthmanager.domain.utils.atStartOfDay
-import ru.rznnike.eyehealthmanager.domain.utils.getTodayCalendar
-import ru.rznnike.eyehealthmanager.domain.utils.toCalendar
-import java.util.Calendar
+import ru.rznnike.eyehealthmanager.domain.utils.millis
+import ru.rznnike.eyehealthmanager.domain.utils.toLocalDate
+import java.time.Clock
@InjectViewState
class ExportJournalPresenter : BasePresenter() {
+ private val clock: Clock by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
private val eventDispatcher: EventDispatcher by inject()
@@ -37,24 +37,18 @@ class ExportJournalPresenter : BasePresenter() {
private var startExportAutomatically = false
override fun onFirstViewAttach() {
- initFilters()
+ clearFilters()
}
- private fun initFilters() {
+ fun clearFilters() {
+ val dateNow = clock.millis().toLocalDate()
filter = TestResultFilter(
- dateFrom = getTodayCalendar().apply {
- add(Calendar.MONTH, -1)
- }.timeInMillis,
- dateTo = Calendar.getInstance().atEndOfDay().timeInMillis
+ dateFrom = dateNow.minusMonths(1).atStartOfDay().millis(),
+ dateTo = dateNow.atEndOfDay().millis()
)
populateData()
}
- fun onClearFilters() {
- initFilters()
- populateData()
- }
-
fun onFilterTestTypeClick(testType: TestType) {
if (filter.selectedTestTypes.contains(testType)) {
filter.selectedTestTypes.remove(testType)
@@ -76,18 +70,18 @@ class ExportJournalPresenter : BasePresenter() {
}
fun onFilterDateFromSelected(timestamp: Long) {
- filter.dateFrom = timestamp.toCalendar().atStartOfDay().timeInMillis
+ filter.dateFrom = timestamp.toLocalDate().atStartOfDay().millis()
if (filter.dateTo <= filter.dateFrom) {
- filter.dateTo = timestamp.toCalendar().atEndOfDay().timeInMillis
+ filter.dateTo = timestamp.toLocalDate().atEndOfDay().millis()
}
filter.filterByDate = true
populateData()
}
fun onFilterDateToSelected(timestamp: Long) {
- filter.dateTo = timestamp.toCalendar().atEndOfDay().timeInMillis
+ filter.dateTo = timestamp.toLocalDate().atEndOfDay().millis()
if (filter.dateTo <= filter.dateFrom) {
- filter.dateFrom = timestamp.toCalendar().atStartOfDay().timeInMillis
+ filter.dateFrom = timestamp.toLocalDate().atStartOfDay().millis()
}
filter.filterByDate = true
populateData()
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/MainPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/MainPresenter.kt
index 72a02943..f56d923f 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/MainPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/MainPresenter.kt
@@ -79,7 +79,7 @@ class MainPresenter : BasePresenter(), EventDispatcher.EventListener {
presenterScope.launch {
val currentVersionCode = BuildConfig.VERSION_CODE
val displayedVersionCode = getDisplayedChangelogVersionUseCase().data ?: currentVersionCode
- if (displayedVersionCode != currentVersionCode) {
+ if (displayedVersionCode < currentVersionCode) {
setDisplayedChangelogVersionUseCase(currentVersionCode)
if (displayedVersionCode > 0) {
viewState.showChangelogDialog()
@@ -96,7 +96,6 @@ class MainPresenter : BasePresenter(), EventDispatcher.EventListener {
notifier.sendAlert(R.string.duplicates_successfully_deleted)
}, ::onError
)
-
eventDispatcher.sendEvent(AppEvent.JournalChanged)
viewState.setProgress(false)
}
@@ -107,10 +106,9 @@ class MainPresenter : BasePresenter(), EventDispatcher.EventListener {
viewState.setProgress(true)
deleteAllTestResultsUseCase().process(
{
- notifier.sendMessage(R.string.clear_journal_success)
+ notifier.sendAlert(R.string.clear_journal_success)
}, ::onError
)
-
eventDispatcher.sendEvent(AppEvent.JournalChanged)
viewState.setProgress(false)
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/journal/JournalPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/journal/JournalPresenter.kt
index 626d3815..f8279d96 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/journal/JournalPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/journal/JournalPresenter.kt
@@ -14,13 +14,23 @@ import ru.rznnike.eyehealthmanager.app.global.presentation.ErrorHandler
import ru.rznnike.eyehealthmanager.app.pagination.Paginator
import ru.rznnike.eyehealthmanager.domain.interactor.test.DeleteTestResultUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.test.GetTestResultsUseCase
-import ru.rznnike.eyehealthmanager.domain.model.*
+import ru.rznnike.eyehealthmanager.domain.model.AcuityTestResult
+import ru.rznnike.eyehealthmanager.domain.model.AstigmatismTestResult
+import ru.rznnike.eyehealthmanager.domain.model.ColorPerceptionTestResult
+import ru.rznnike.eyehealthmanager.domain.model.ContrastTestResult
+import ru.rznnike.eyehealthmanager.domain.model.DaltonismTestResult
+import ru.rznnike.eyehealthmanager.domain.model.NearFarTestResult
+import ru.rznnike.eyehealthmanager.domain.model.TestResult
+import ru.rznnike.eyehealthmanager.domain.model.TestResultFilter
+import ru.rznnike.eyehealthmanager.domain.model.TestResultPagingParameters
import ru.rznnike.eyehealthmanager.domain.utils.atEndOfDay
-import ru.rznnike.eyehealthmanager.domain.utils.getTodayCalendar
-import java.util.*
+import ru.rznnike.eyehealthmanager.domain.utils.millis
+import ru.rznnike.eyehealthmanager.domain.utils.toLocalDate
+import java.time.Clock
@InjectViewState
class JournalPresenter : BasePresenter(), EventDispatcher.EventListener {
+ private val clock: Clock by inject()
private val eventDispatcher: EventDispatcher by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
@@ -153,11 +163,10 @@ class JournalPresenter : BasePresenter(), EventDispatcher.EventList
}
private fun setDefaultFilter() {
+ val dateNow = clock.millis().toLocalDate()
filter = TestResultFilter(
- dateFrom = getTodayCalendar().apply {
- add(Calendar.MONTH, -1)
- }.timeInMillis,
- dateTo = Calendar.getInstance().atEndOfDay().timeInMillis
+ dateFrom = dateNow.minusMonths(1).atStartOfDay().millis(),
+ dateTo = dateNow.atEndOfDay().millis()
)
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/settings/SettingsPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/settings/SettingsPresenter.kt
index 2812203d..0ab9a73f 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/settings/SettingsPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/settings/SettingsPresenter.kt
@@ -11,9 +11,13 @@ import ru.rznnike.eyehealthmanager.app.dispatcher.event.EventDispatcher
import ru.rznnike.eyehealthmanager.app.dispatcher.notifier.Notifier
import ru.rznnike.eyehealthmanager.app.global.presentation.BasePresenter
import ru.rznnike.eyehealthmanager.app.global.presentation.ErrorHandler
+import ru.rznnike.eyehealthmanager.app.utils.extensions.applyTheme
import ru.rznnike.eyehealthmanager.domain.interactor.dev.GenerateDataUseCase
+import ru.rznnike.eyehealthmanager.domain.interactor.user.GetAppThemeUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.user.GetUserLanguageUseCase
+import ru.rznnike.eyehealthmanager.domain.interactor.user.SetAppThemeUseCase
import ru.rznnike.eyehealthmanager.domain.interactor.user.SetUserLanguageUseCase
+import ru.rznnike.eyehealthmanager.domain.model.enums.AppTheme
import ru.rznnike.eyehealthmanager.domain.model.enums.DataGenerationType
import ru.rznnike.eyehealthmanager.domain.model.enums.Language
@@ -24,18 +28,39 @@ class SettingsPresenter : BasePresenter() {
private val eventDispatcher: EventDispatcher by inject()
private val getUserLanguageUseCase: GetUserLanguageUseCase by inject()
private val setUserLanguageUseCase: SetUserLanguageUseCase by inject()
+ private val getAppThemeUseCase: GetAppThemeUseCase by inject()
+ private val setAppThemeUseCase: SetAppThemeUseCase by inject()
private val generateDataUseCase: GenerateDataUseCase by inject()
- fun onResume() {
+ private var language = Language.EN
+ private var theme = AppTheme.SYSTEM
+
+ override fun onFirstViewAttach() {
+ initData()
+ }
+
+ private fun initData() {
presenterScope.launch {
getUserLanguageUseCase().process(
- {
- viewState.populateData(it)
- }
+ { result ->
+ language = result
+ }, ::onError
+ )
+ getAppThemeUseCase().process(
+ { result ->
+ theme = result
+ }, ::onError
)
+ populateData()
}
}
+ private fun populateData() =
+ viewState.populateData(
+ language = language,
+ theme = theme
+ )
+
fun changeLanguage(language: Language) {
presenterScope.launch {
viewState.setProgress(true)
@@ -48,6 +73,18 @@ class SettingsPresenter : BasePresenter() {
}
}
+ fun changeTheme(newTheme: AppTheme) {
+ presenterScope.launch {
+ setAppThemeUseCase(newTheme).process(
+ {
+ theme = newTheme
+ populateData()
+ }, ::onError
+ )
+ applyTheme(newTheme)
+ }
+ }
+
fun openTestingSettings() = viewState.routerNavigateTo(Screens.Screen.testingSettings())
fun openAnalysis() = viewState.routerStartFlow(Screens.Flow.analysis())
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/settings/SettingsView.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/settings/SettingsView.kt
index 4d3dc4d6..0996cd2e 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/settings/SettingsView.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/main/settings/SettingsView.kt
@@ -3,6 +3,7 @@ package ru.rznnike.eyehealthmanager.app.presentation.main.settings
import moxy.viewstate.strategy.alias.AddToEndSingle
import moxy.viewstate.strategy.alias.OneExecution
import ru.rznnike.eyehealthmanager.app.global.presentation.NavigationMvpView
+import ru.rznnike.eyehealthmanager.domain.model.enums.AppTheme
import ru.rznnike.eyehealthmanager.domain.model.enums.Language
interface SettingsView : NavigationMvpView {
@@ -10,7 +11,7 @@ interface SettingsView : NavigationMvpView {
fun setProgress(show: Boolean, immediately: Boolean = true)
@AddToEndSingle
- fun populateData(currentLanguage: Language)
+ fun populateData(language: Language, theme: AppTheme)
@OneExecution
fun updateUiLanguage()
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/answer/NearFarAnswerPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/answer/NearFarAnswerPresenter.kt
index a70e3b84..18ec5e09 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/answer/NearFarAnswerPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/answer/NearFarAnswerPresenter.kt
@@ -13,9 +13,11 @@ import ru.rznnike.eyehealthmanager.app.global.presentation.ErrorHandler
import ru.rznnike.eyehealthmanager.domain.interactor.test.AddTestResultUseCase
import ru.rznnike.eyehealthmanager.domain.model.NearFarTestResult
import ru.rznnike.eyehealthmanager.domain.model.enums.NearFarAnswerType
+import java.time.Clock
@InjectViewState
class NearFarAnswerPresenter : BasePresenter() {
+ private val clock: Clock by inject()
private val errorHandler: ErrorHandler by inject()
private val notifier: Notifier by inject()
private val eventDispatcher: EventDispatcher by inject()
@@ -28,7 +30,7 @@ class NearFarAnswerPresenter : BasePresenter() {
val typeRightEye = NearFarAnswerType.entries[answerRightEye]
val testResult = NearFarTestResult(
- timestamp = System.currentTimeMillis(),
+ timestamp = clock.millis(),
resultRightEye = typeRightEye,
resultLeftEye = typeLeftEye
)
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/info/NearFarInfoPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/info/NearFarInfoPresenter.kt
index 2b8a57bb..e69dd4af 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/info/NearFarInfoPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/info/NearFarInfoPresenter.kt
@@ -6,7 +6,5 @@ import ru.rznnike.eyehealthmanager.app.global.presentation.BasePresenter
@InjectViewState
class NearFarInfoPresenter : BasePresenter() {
- fun startTest() {
- viewState.routerNewRootScreen(Screens.Screen.nearFarTest())
- }
+ fun startTest() = viewState.routerNewRootScreen(Screens.Screen.nearFarTest())
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/test/NearFarTestPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/test/NearFarTestPresenter.kt
index 6b8fd51f..85805802 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/test/NearFarTestPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/nearfar/test/NearFarTestPresenter.kt
@@ -6,7 +6,5 @@ import ru.rznnike.eyehealthmanager.app.global.presentation.BasePresenter
@InjectViewState
class NearFarTestPresenter : BasePresenter() {
- fun openAnswerForm() {
- viewState.routerNavigateTo(Screens.Screen.nearFarAnswer())
- }
+ fun openAnswerForm() = viewState.routerNavigateTo(Screens.Screen.nearFarAnswer())
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/settings/testing/TestingSettingsPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/settings/testing/TestingSettingsPresenter.kt
index caa03cb2..10894f25 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/settings/testing/TestingSettingsPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/settings/testing/TestingSettingsPresenter.kt
@@ -16,8 +16,6 @@ import ru.rznnike.eyehealthmanager.domain.model.TestingSettings
import ru.rznnike.eyehealthmanager.domain.utils.GlobalConstants
import ru.rznnike.eyehealthmanager.domain.utils.getDayTime
-private const val MIN_DELTA_IN_MS = 60 * 1000L // 1m
-
@InjectViewState
class TestingSettingsPresenter : BasePresenter() {
private val errorHandler: ErrorHandler by inject()
@@ -52,8 +50,8 @@ class TestingSettingsPresenter : BasePresenter() {
}, { error ->
errorHandler.proceed(error) {
notifier.sendMessage(it)
- viewState.routerExit()
}
+ viewState.routerExit()
}
)
}
@@ -118,19 +116,19 @@ class TestingSettingsPresenter : BasePresenter() {
if (!isTimeOrderCorrect(settings)) {
when (period) {
TimePeriod.BEGINNING -> {
- settings.timeToDayBeginning = settings.timeToDayEnd + MIN_DELTA_IN_MS
+ settings.timeToDayBeginning = settings.timeToDayEnd + GlobalConstants.MINUTE_MS
if (settings.timeToDayBeginning >= GlobalConstants.DAY_MS) {
settings.timeToDayBeginning -= GlobalConstants.DAY_MS
}
}
TimePeriod.MIDDLE -> {
- settings.timeToDayMiddle = settings.timeToDayBeginning + MIN_DELTA_IN_MS
+ settings.timeToDayMiddle = settings.timeToDayBeginning + GlobalConstants.MINUTE_MS
if (settings.timeToDayMiddle >= GlobalConstants.DAY_MS) {
settings.timeToDayMiddle -= GlobalConstants.DAY_MS
}
}
TimePeriod.END -> {
- settings.timeToDayEnd = settings.timeToDayMiddle + MIN_DELTA_IN_MS
+ settings.timeToDayEnd = settings.timeToDayMiddle + GlobalConstants.MINUTE_MS
if (settings.timeToDayEnd >= GlobalConstants.DAY_MS) {
settings.timeToDayEnd -= GlobalConstants.DAY_MS
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/splash/SplashPresenter.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/splash/SplashPresenter.kt
index f0fa4067..65d66100 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/splash/SplashPresenter.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/presentation/splash/SplashPresenter.kt
@@ -6,7 +6,5 @@ import ru.rznnike.eyehealthmanager.app.global.presentation.BasePresenter
@InjectViewState
class SplashPresenter : BasePresenter() {
- fun onAnimationEnd() {
- viewState.routerNewRootFlow(Screens.Flow.main())
- }
+ fun onAnimationEnd() = viewState.routerNewRootFlow(Screens.Flow.main())
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/analysis/result/AnalysisResultFragment.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/analysis/result/AnalysisResultFragment.kt
index f192f06e..b5058722 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/analysis/result/AnalysisResultFragment.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/analysis/result/AnalysisResultFragment.kt
@@ -217,6 +217,7 @@ class AnalysisResultFragment : BaseFragment(R.layout.fragment_analysis_result),
color = context.getColor(baseColorResId)
setCircleColor(context.getColor(R.color.colorTransparent))
circleHoleColor = context.getColor(baseColorResId)
+ valueTextColor = context.getColor(R.color.colorText)
}
chartVisionDynamic.data.addDataSet(baseDataSet)
@@ -240,6 +241,7 @@ class AnalysisResultFragment : BaseFragment(R.layout.fragment_analysis_result),
color = context.getColor(extrapolationColorResId)
setCircleColor(context.getColor(R.color.colorTransparent))
circleHoleColor = context.getColor(extrapolationColorResId)
+ valueTextColor = context.getColor(R.color.colorText)
}
chartVisionDynamic.data.addDataSet(extrapolationDataSet)
@@ -258,6 +260,7 @@ class AnalysisResultFragment : BaseFragment(R.layout.fragment_analysis_result),
axisLeft.apply {
axisMinimum = 0f
axisMaximum = yAxisMaximum + 0.05f
+ textColor = context.getColor(R.color.colorTextDark)
}
xAxis.apply {
axisMinimum = xAxisMinimum
@@ -270,8 +273,12 @@ class AnalysisResultFragment : BaseFragment(R.layout.fragment_analysis_result),
return value.toLong().toDate()
}
}
+ textColor = context.getColor(R.color.colorTextDark)
+ }
+ legend.apply {
+ isWordWrapEnabled = true
+ textColor = context.getColor(R.color.colorText)
}
- legend.isWordWrapEnabled = true
}
companion object {
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/contrast/test/ContrastTestFragment.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/contrast/test/ContrastTestFragment.kt
index 820c3749..95ccb3c5 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/contrast/test/ContrastTestFragment.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/contrast/test/ContrastTestFragment.kt
@@ -74,16 +74,16 @@ class ContrastTestFragment : BaseFragment(R.layout.fragment_contrast_test), Cont
private fun initOnClickListeners() = binding.apply {
buttonUp.setOnClickListener {
- presenter.onAnswer(Direction.UP)
+ presenter.answer(Direction.UP)
}
buttonDown.setOnClickListener {
- presenter.onAnswer(Direction.DOWN)
+ presenter.answer(Direction.DOWN)
}
buttonLeft.setOnClickListener {
- presenter.onAnswer(Direction.LEFT)
+ presenter.answer(Direction.LEFT)
}
buttonRight.setOnClickListener {
- presenter.onAnswer(Direction.RIGHT)
+ presenter.answer(Direction.RIGHT)
}
}
@@ -107,7 +107,7 @@ class ContrastTestFragment : BaseFragment(R.layout.fragment_contrast_test), Cont
it.isEnabled = false
}
- layoutTest.animate()
+ layoutTestFigure.animate()
.alpha(0f)
.setStartDelay(0)
.setDuration(FADE_ANIMATION_MS)
@@ -122,8 +122,8 @@ class ContrastTestFragment : BaseFragment(R.layout.fragment_contrast_test), Cont
}
imageViewForeground.setImageResource(imageRes)
- layoutTest.setVisible()
- layoutTest.animate()
+ layoutTestFigure.setVisible()
+ layoutTestFigure.animate()
.alpha(1f)
.setStartDelay(0)
.setDuration(FADE_ANIMATION_MS)
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/daltonism/result/DaltonismResultFragment.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/daltonism/result/DaltonismResultFragment.kt
index 91911065..26a35d1e 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/daltonism/result/DaltonismResultFragment.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/daltonism/result/DaltonismResultFragment.kt
@@ -23,7 +23,7 @@ class DaltonismResultFragment : BaseFragment(R.layout.fragment_daltonism_result)
@ProvidePresenter
fun providePresenter() = DaltonismResultPresenter(
errorsCount = getIntArg(ERRORS_COUNT),
- resultType = DaltonismAnomalyType[getStringArg(RESULT_TYPE)] ?: DaltonismAnomalyType.NONE
+ resultType = getParcelableArg(RESULT_TYPE) ?: DaltonismAnomalyType.NONE
)
private val binding by viewBinding(FragmentDaltonismResultBinding::bind)
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/daltonism/test/DaltonismTestFragment.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/daltonism/test/DaltonismTestFragment.kt
index 8acbce52..3f658b9a 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/daltonism/test/DaltonismTestFragment.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/daltonism/test/DaltonismTestFragment.kt
@@ -66,7 +66,7 @@ class DaltonismTestFragment : BaseFragment(R.layout.fragment_daltonism_test), Da
buttonVariant4
).forEachIndexed { index, button ->
button.setOnClickListener {
- presenter.onAnswer(index)
+ presenter.answer(index)
}
}
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/journal/backup/ExportJournalFragment.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/journal/backup/ExportJournalFragment.kt
index 04a9c0c7..ca34789f 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/journal/backup/ExportJournalFragment.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/journal/backup/ExportJournalFragment.kt
@@ -120,7 +120,7 @@ class ExportJournalFragment : BaseFragment(R.layout.fragment_export_journal), Ex
private fun initOnClickListeners() = binding.apply {
buttonClearFilters.setOnClickListener {
- presenter.onClearFilters()
+ presenter.clearFilters()
}
checkBoxFilterByDate.setOnClickListener {
presenter.onFilterByDateValueChanged(checkBoxFilterByDate.isChecked)
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/main/journal/JournalFragment.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/main/journal/JournalFragment.kt
index e4b34346..ba6c90a1 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/main/journal/JournalFragment.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/main/journal/JournalFragment.kt
@@ -37,9 +37,9 @@ import ru.rznnike.eyehealthmanager.domain.model.TestResultFilter
import ru.rznnike.eyehealthmanager.domain.model.enums.TestType
import ru.rznnike.eyehealthmanager.domain.utils.GlobalConstants
import ru.rznnike.eyehealthmanager.domain.utils.atEndOfDay
-import ru.rznnike.eyehealthmanager.domain.utils.atStartOfDay
-import ru.rznnike.eyehealthmanager.domain.utils.toCalendar
+import ru.rznnike.eyehealthmanager.domain.utils.millis
import ru.rznnike.eyehealthmanager.domain.utils.toDate
+import ru.rznnike.eyehealthmanager.domain.utils.toLocalDate
class JournalFragment : BaseFragment(R.layout.fragment_journal), JournalView {
@InjectPresenter
@@ -294,9 +294,9 @@ class JournalFragment : BaseFragment(R.layout.fragment_journal), JournalView {
showDatePicker(
preselectedDate = newFilter.dateFrom
) { timestamp ->
- newFilter.dateFrom = timestamp.toCalendar().atStartOfDay().timeInMillis
+ newFilter.dateFrom = timestamp.toLocalDate().atStartOfDay().millis()
if (newFilter.dateTo <= newFilter.dateFrom) {
- newFilter.dateTo = timestamp.toCalendar().atEndOfDay().timeInMillis
+ newFilter.dateTo = timestamp.toLocalDate().atEndOfDay().millis()
}
newFilter.filterByDate = true
updateDates()
@@ -306,9 +306,9 @@ class JournalFragment : BaseFragment(R.layout.fragment_journal), JournalView {
showDatePicker(
preselectedDate = newFilter.dateTo
) { timestamp ->
- newFilter.dateTo = timestamp.toCalendar().atEndOfDay().timeInMillis
+ newFilter.dateTo = timestamp.toLocalDate().atEndOfDay().millis()
if (newFilter.dateTo <= newFilter.dateFrom) {
- newFilter.dateFrom = timestamp.toCalendar().atStartOfDay().timeInMillis
+ newFilter.dateFrom = timestamp.toLocalDate().atStartOfDay().millis()
}
newFilter.filterByDate = true
updateDates()
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/main/settings/SettingsFragment.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/main/settings/SettingsFragment.kt
index f52bff97..91bfdb85 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/main/settings/SettingsFragment.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/main/settings/SettingsFragment.kt
@@ -24,6 +24,7 @@ import ru.rznnike.eyehealthmanager.databinding.DialogAboutAppBinding
import ru.rznnike.eyehealthmanager.databinding.DialogChangelogBinding
import ru.rznnike.eyehealthmanager.databinding.DialogDevMenuBinding
import ru.rznnike.eyehealthmanager.databinding.FragmentSettingsBinding
+import ru.rznnike.eyehealthmanager.domain.model.enums.AppTheme
import ru.rznnike.eyehealthmanager.domain.model.enums.DataGenerationType
import ru.rznnike.eyehealthmanager.domain.model.enums.Language
import ru.rznnike.eyehealthmanager.domain.utils.GlobalConstants
@@ -49,11 +50,6 @@ class SettingsFragment : BaseFragment(R.layout.fragment_settings), SettingsView
initOnClickListeners()
}
- override fun onResume() {
- super.onResume()
- presenter.onResume()
- }
-
private fun initViews() = binding.apply {
listOf(
buttonTestingSettings,
@@ -63,6 +59,7 @@ class SettingsFragment : BaseFragment(R.layout.fragment_settings), SettingsView
buttonDeleteDuplicates,
buttonClearJournal,
buttonLanguage,
+ buttonTheme,
buttonAboutApp,
buttonChangelog,
buttonDevMenu
@@ -103,11 +100,15 @@ class SettingsFragment : BaseFragment(R.layout.fragment_settings), SettingsView
}
}
- override fun populateData(currentLanguage: Language) {
+ override fun populateData(language: Language, theme: AppTheme) {
binding.apply {
- textViewCurrentLanguage.text = currentLanguage.localizedName
+ textViewCurrentLanguage.text = language.localizedName
buttonLanguage.setOnClickListener {
- showLanguageSelectionBottomDialog(currentLanguage)
+ showLanguageSelectionBottomDialog(language)
+ }
+ textViewCurrentTheme.setText(theme.nameResId)
+ buttonTheme.setOnClickListener {
+ showThemeSelectionBottomDialog(theme)
}
}
}
@@ -129,6 +130,21 @@ class SettingsFragment : BaseFragment(R.layout.fragment_settings), SettingsView
override fun updateUiLanguage() = requireActivity().restartApp()
+ private fun showThemeSelectionBottomDialog(currentTheme: AppTheme) {
+ showBottomDialog(
+ header = getString(R.string.choose_theme),
+ actions = AppTheme.entries.map { theme ->
+ BottomDialogAction(
+ text = getString(theme.nameResId),
+ selected = theme == currentTheme
+ ) {
+ it.dismiss()
+ presenter.changeTheme(theme)
+ }
+ }
+ )
+ }
+
private fun showClearJournalDialog() {
showAlertDialog(
parameters = AlertDialogParameters.HORIZONTAL_2_OPTIONS_LEFT_ACCENT,
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/settings/testing/TestingSettingsFragment.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/settings/testing/TestingSettingsFragment.kt
index e382c687..78e8f3ab 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/settings/testing/TestingSettingsFragment.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/fragment/settings/testing/TestingSettingsFragment.kt
@@ -104,15 +104,18 @@ class TestingSettingsFragment : BaseFragment(R.layout.fragment_settings_testing)
viewTimeControlsDisabler.setVisible(!settings.enableAutoDayPart)
- val calendar = Calendar.getInstance()
- val timeToDayBeginningWithOffset = settings.timeToDayBeginning - calendar.timeZone.rawOffset
- val timeToDayBeginningText = timeToDayBeginningWithOffset.toDate(GlobalConstants.DATE_PATTERN_CLOCK)
-
- val timeToDayMiddleWithOffset = settings.timeToDayMiddle - calendar.timeZone.rawOffset
- val timeToDayMiddleText = timeToDayMiddleWithOffset.toDate(GlobalConstants.DATE_PATTERN_CLOCK)
-
- val timeToDayEndWithOffset = settings.timeToDayEnd - calendar.timeZone.rawOffset
- val timeToDayEndText = timeToDayEndWithOffset.toDate(GlobalConstants.DATE_PATTERN_CLOCK)
+ val timeToDayBeginningText = settings.timeToDayBeginning.toDate(
+ pattern = GlobalConstants.DATE_PATTERN_CLOCK,
+ zeroTimeZone = true
+ )
+ val timeToDayMiddleText = settings.timeToDayMiddle.toDate(
+ pattern = GlobalConstants.DATE_PATTERN_CLOCK,
+ zeroTimeZone = true
+ )
+ val timeToDayEndText = settings.timeToDayEnd.toDate(
+ pattern = GlobalConstants.DATE_PATTERN_CLOCK,
+ zeroTimeZone = true
+ )
buttonTimeToBeginning1.text = timeToDayBeginningText
buttonTimeToBeginning2.text = timeToDayBeginningText
@@ -121,10 +124,11 @@ class TestingSettingsFragment : BaseFragment(R.layout.fragment_settings_testing)
buttonTimeToEnd1.text = timeToDayEndText
buttonTimeToEnd2.text = timeToDayEndText
+ val zoneOffset = TimeZone.getDefault().rawOffset
listOf(buttonTimeToBeginning1, buttonTimeToBeginning2).forEach {
it.setOnClickListener {
showTimePicker(
- preselectedTime = timeToDayBeginningWithOffset,
+ preselectedTime = settings.timeToDayBeginning - zoneOffset,
onSuccess = presenter::onTimeToDayBeginningValueChanged
)
}
@@ -132,7 +136,7 @@ class TestingSettingsFragment : BaseFragment(R.layout.fragment_settings_testing)
listOf(buttonTimeToMiddle1, buttonTimeToMiddle2).forEach {
it.setOnClickListener {
showTimePicker(
- preselectedTime = timeToDayMiddleWithOffset,
+ preselectedTime = settings.timeToDayMiddle - zoneOffset,
onSuccess = presenter::onTimeToDayMiddleValueChanged
)
}
@@ -140,7 +144,7 @@ class TestingSettingsFragment : BaseFragment(R.layout.fragment_settings_testing)
listOf(buttonTimeToEnd1, buttonTimeToEnd2).forEach {
it.setOnClickListener {
showTimePicker(
- preselectedTime = timeToDayEndWithOffset,
+ preselectedTime = settings.timeToDayEnd - zoneOffset,
onSuccess = presenter::onTimeToDayEndValueChanged
)
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/view/PercentProgressView.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/view/PercentProgressView.kt
index c9707255..9a89796f 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/view/PercentProgressView.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/ui/view/PercentProgressView.kt
@@ -37,12 +37,12 @@ class PercentProgressView @JvmOverloads constructor(
}
private fun updateMax() = binding.apply {
- progressBar.max = max * PROGRESS_MULTIPLIER
+ percentProgressBar.max = max * PROGRESS_MULTIPLIER
}
private fun updateProgress() = binding.apply {
textViewProgress.text = "%d%%".format(progress)
- ObjectAnimator.ofInt(progressBar, "progress", progress * PROGRESS_MULTIPLIER)
+ ObjectAnimator.ofInt(percentProgressBar, "progress", progress * PROGRESS_MULTIPLIER)
.setDuration(PROGRESS_ANIMATION_MS)
.start()
}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/ActivityUtils.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/ActivityUtils.kt
index 6a1126c2..a1d1d535 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/ActivityUtils.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/ActivityUtils.kt
@@ -2,6 +2,8 @@ package ru.rznnike.eyehealthmanager.app.utils.extensions
import android.app.Activity
import android.content.Intent
+import androidx.appcompat.app.AppCompatDelegate
+import ru.rznnike.eyehealthmanager.domain.model.enums.AppTheme
import kotlin.system.exitProcess
fun Activity.restartApp() {
@@ -10,3 +12,12 @@ fun Activity.restartApp() {
startActivity(restartIntent)
exitProcess(0)
}
+
+fun applyTheme(theme: AppTheme) {
+ val flag = when (theme) {
+ AppTheme.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
+ AppTheme.DARK -> AppCompatDelegate.MODE_NIGHT_YES
+ AppTheme.SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
+ }
+ AppCompatDelegate.setDefaultNightMode(flag)
+}
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/ContextUtils.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/ContextUtils.kt
index 3b7cb19e..06cc4830 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/ContextUtils.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/ContextUtils.kt
@@ -2,6 +2,7 @@ package ru.rznnike.eyehealthmanager.app.utils.extensions
import android.app.Activity
import android.content.Context
+import android.content.res.Configuration
import android.graphics.Rect
import android.util.DisplayMetrics
import android.util.TypedValue
@@ -40,3 +41,9 @@ val Activity.deviceSize: Rect
get() = WindowMetricsCalculator.getOrCreate()
.computeCurrentWindowMetrics(this)
.bounds
+
+val Context.isNightModeEnabled: Boolean
+ get() {
+ val uiModeFlag = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+ return uiModeFlag == Configuration.UI_MODE_NIGHT_YES
+ }
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/EditTextUtils.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/EditTextUtils.kt
index ee330c2e..36c769ab 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/EditTextUtils.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/EditTextUtils.kt
@@ -49,7 +49,7 @@ fun EditText?.removeFocusAndSpan() {
fun EditText.setOnKeyboardActionListener(keyId: Int, action: () -> Unit) {
setOnEditorActionListener { _, actionId, _ ->
if (actionId == keyId) {
- action.invoke()
+ action()
true
} else {
false
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/StringUtils.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/StringUtils.kt
index df5b8e7d..2be9fa12 100644
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/StringUtils.kt
+++ b/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/StringUtils.kt
@@ -1,76 +1,12 @@
package ru.rznnike.eyehealthmanager.app.utils.extensions
-import android.text.SpannableStringBuilder
-import android.text.Spanned
-import android.text.TextPaint
-import android.text.style.ClickableSpan
-import android.view.View
import androidx.core.text.HtmlCompat
-import androidx.core.text.inSpans
-import java.util.*
+import java.util.Locale
fun String.toHtmlSpanned() = HtmlCompat.fromHtml(this, HtmlCompat.FROM_HTML_MODE_LEGACY)
-fun getHexFromColor(color: Int) = String.format("#%06X", 0xFFFFFF and color)
-
fun String.capitalize() = replaceFirstChar {
if (it.isLowerCase()) it.titlecase(
Locale.getDefault()
) else it.toString()
-}
-
-fun createStringWithClickableSpans(
- template: String,
- clickableTexts: List Unit>>
-): Spanned {
- fun getClickableSpan(onClickListener: () -> Unit) = object : ClickableSpan() {
- override fun onClick(textView: View) = onClickListener()
-
- override fun updateDrawState(ds: TextPaint) {
- super.updateDrawState(ds)
- ds.isUnderlineText = false
- }
- }
-
- val stringBuilder = SpannableStringBuilder()
- template.split("%s").forEachIndexed { index, part ->
- if (index > 0) {
- val spanIndex = index - 1
- clickableTexts.getOrNull(spanIndex)?.let { spanData ->
- stringBuilder.inSpans(getClickableSpan(spanData.second)) {
- append(spanData.first.toHtmlSpanned())
- }
- }
- }
- "^ +".toRegex().find(part)?.let { match ->
- stringBuilder.append(match.value)
- }
- stringBuilder.append(
- part.replace("\n".toRegex(), "
")
- .toHtmlSpanned()
- )
- }
-
- return stringBuilder
-}
-
-fun createStringWithHighlights(
- text: String,
- partsToHighlight: List,
- highlightColor: Int
-): Spanned {
- val highlightColorHex = getHexFromColor(highlightColor)
-
- var resultText = text
- partsToHighlight.forEach { part ->
- resultText = resultText.replaceFirst(
- part,
- "%s".format(
- highlightColorHex,
- part
- )
- )
- }
-
- return resultText.replace("\n".toRegex(), "
").toHtmlSpanned()
}
\ No newline at end of file
diff --git a/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/TextViewUtils.kt b/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/TextViewUtils.kt
deleted file mode 100644
index 0f8c851e..00000000
--- a/app/src/main/java/ru/rznnike/eyehealthmanager/app/utils/extensions/TextViewUtils.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package ru.rznnike.eyehealthmanager.app.utils.extensions
-
-import android.text.SpannableString
-import android.text.TextPaint
-import android.text.style.ClickableSpan
-import android.text.style.URLSpan
-import android.view.View
-import android.widget.TextView
-
-fun TextView.removeLinkUnderlines(clickCallback: ((String) -> Unit)? = null) {
- val spannable = SpannableString(text)
- val spans = spannable.getSpans(0, spannable.length, URLSpan::class.java)
- for (span in spans) {
- val start = spannable.getSpanStart(span)
- val end = spannable.getSpanEnd(span)
- val newSpan = clickCallback?.let {
- ClickableSpanNoUnderline(span.url, clickCallback)
- } ?: run {
- URLSpanNoUnderline(span.url)
- }
- spannable.removeSpan(span)
- spannable.setSpan(newSpan, start, end, 0)
- }
- text = spannable
-}
-
-private class URLSpanNoUnderline(
- url: String
-) : URLSpan(url) {
- override fun updateDrawState(textPaint: TextPaint) {
- super.updateDrawState(textPaint)
- textPaint.isUnderlineText = false
- }
-}
-
-private class ClickableSpanNoUnderline(
- val url: String,
- val clickCallback: ((String) -> Unit)
-) : ClickableSpan() {
- override fun updateDrawState(textPaint: TextPaint) {
- super.updateDrawState(textPaint)
- textPaint.isUnderlineText = false
- }
-
- override fun onClick(widget: View) {
- clickCallback.invoke(url)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_about_app.xml b/app/src/main/res/layout/dialog_about_app.xml
index a5cb6b02..5fd3fb87 100644
--- a/app/src/main/res/layout/dialog_about_app.xml
+++ b/app/src/main/res/layout/dialog_about_app.xml
@@ -1,6 +1,5 @@
+ android:layout_height="16dp" />
-
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layout_marginHorizontal="16dp"
+ android:background="@drawable/bg_rounded_8"
+ android:backgroundTint="@color/colorBackgroundTestWhite">
+
+
+
+
+ android:layout_height="16dp" />
@@ -114,30 +128,50 @@
tools:visibility="visible">
+ android:layout_width="match_parent"
+ android:layout_height="16dp" />
-
+ android:background="@drawable/bg_rounded_8"
+ android:backgroundTint="@color/colorBackgroundTestWhite">
+
+
+
+
+
+
-
+ android:layout_height="16dp" />
diff --git a/app/src/main/res/layout/fragment_astigmatism_test.xml b/app/src/main/res/layout/fragment_astigmatism_test.xml
index 85c39f03..2d18865e 100644
--- a/app/src/main/res/layout/fragment_astigmatism_test.xml
+++ b/app/src/main/res/layout/fragment_astigmatism_test.xml
@@ -1,9 +1,9 @@
-
-
+ android:layout_marginHorizontal="16dp"
+ android:background="@drawable/bg_rounded_8"
+ android:backgroundTint="@color/colorBackgroundTestWhite">
-
+
-
+
-
+
-
-
-
-
-
+ android:layout_margin="100dp">
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_cant_answer.xml b/app/src/main/res/layout/item_cant_answer.xml
index 4e44f2bd..bf55791f 100644
--- a/app/src/main/res/layout/item_cant_answer.xml
+++ b/app/src/main/res/layout/item_cant_answer.xml
@@ -5,7 +5,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_rounded_8"
- android:backgroundTint="@color/colorBackground"
+ android:backgroundTint="@color/colorBackgroundInvariant"
android:orientation="horizontal">
diff --git a/app/src/main/res/layout/item_symbol.xml b/app/src/main/res/layout/item_symbol.xml
index 9bc67575..c5ac897c 100644
--- a/app/src/main/res/layout/item_symbol.xml
+++ b/app/src/main/res/layout/item_symbol.xml
@@ -2,10 +2,10 @@
+ tools:src="@drawable/ic_letters_en_f"/>
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_percent_progress.xml b/app/src/main/res/layout/view_percent_progress.xml
index 6a309c8f..07d139d0 100644
--- a/app/src/main/res/layout/view_percent_progress.xml
+++ b/app/src/main/res/layout/view_percent_progress.xml
@@ -7,7 +7,7 @@
android:gravity="center">
-
+
+