diff --git a/README.md b/README.md new file mode 100644 index 0000000..2fb9b28 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Wind of Win +### PenPot: https://pp.sicampus.ru/#/workspace?team-id=14a6b474-d5fa-807f-8007-9f077869482e&file-id=14a6b474-d5fa-807f-8007-9f510e3bd124&page-id=14a6b474-d5fa-807f-8007-9f510e3bd125&layout=assets \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a70cefb..3735abe 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -34,6 +34,9 @@ android { } dependencies { + implementation("androidx.compose.ui:ui-tooling-preview:1.10.3") + implementation("androidx.wear.tiles:tiles-tooling-preview:1.5.0") + debugImplementation("androidx.compose.ui:ui-tooling:1.10.3") defaultComposeLibrary() implementation("androidx.datastore:datastore-preferences:1.1.7") implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0") diff --git a/app/src/main/java/ru/myitschool/work/App.kt b/app/src/main/java/ru/myitschool/work/App.kt index aa33483..21d93f4 100644 --- a/app/src/main/java/ru/myitschool/work/App.kt +++ b/app/src/main/java/ru/myitschool/work/App.kt @@ -8,7 +8,6 @@ class App: Application() { super.onCreate() context = this } - companion object { lateinit var context: Context } diff --git a/app/src/main/java/ru/myitschool/work/core/Constants.kt b/app/src/main/java/ru/myitschool/work/core/Constants.kt index cd36239..3852103 100644 --- a/app/src/main/java/ru/myitschool/work/core/Constants.kt +++ b/app/src/main/java/ru/myitschool/work/core/Constants.kt @@ -1,7 +1,7 @@ package ru.myitschool.work.core object Constants { - const val HOST = "http://localhost:8090" + const val HOST = "http://10.0.0.172:49182" // "http://10.0.0.14:49182" or "http://10.0.2.2:8080" const val AUTH_URL = "/auth" const val INFO_URL = "/info" const val BOOKING_URL = "/booking" diff --git a/app/src/main/java/ru/myitschool/work/core/TestIds.kt b/app/src/main/java/ru/myitschool/work/core/TestIds.kt index d67b884..048ea60 100644 --- a/app/src/main/java/ru/myitschool/work/core/TestIds.kt +++ b/app/src/main/java/ru/myitschool/work/core/TestIds.kt @@ -4,7 +4,8 @@ object TestIds { object Auth { const val ERROR = "auth_error" const val SIGN_BUTTON = "auth_sign_button" - const val CODE_INPUT = "auth_code_input" + const val LOGIN_INPUT = "auth_login_input" + const val PASSWORD_INPUT = "auth_password_input" } object Main { const val ERROR = "main_error" diff --git a/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt b/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt index e4126dd..f58a11f 100644 --- a/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt +++ b/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt @@ -1,6 +1,7 @@ package ru.myitschool.work.data.repo import android.content.Context +import android.util.Log import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit @@ -12,37 +13,47 @@ import ru.myitschool.work.data.source.NetworkDataSource object AuthRepository { private const val STORE = "AUTH-STORE" - private const val CODE_KEY = "CODE" - - private var codeCache: String? = null - + private const val TOKEN_KEY = "TOKEN" + private var tokenCache: String? = null suspend fun checkAndSave(text: String): Result { return NetworkDataSource.checkAuth(text).onSuccess { success -> if (success) { - codeCache = text + tokenCache = text App.context.userDataStore.edit { preferences -> - val prefKey = stringPreferencesKey(CODE_KEY) + val prefKey = stringPreferencesKey(TOKEN_KEY) preferences[prefKey] = text } } } } - suspend fun getCode(): String? { - if (codeCache == null) { - codeCache = App.context.userDataStore.data + /** + * Из памяти + */ + suspend fun auth(): String? { + if (tokenCache == null) { + tokenCache = App.context.userDataStore.data .firstOrNull() ?.let { preferences -> - preferences[stringPreferencesKey(CODE_KEY)] + preferences[stringPreferencesKey(TOKEN_KEY)] } } - return codeCache + Log.e("getTokenCache", tokenCache.toString()) + return tokenCache + } + + /** + * При обращении к серверу + */ + suspend fun auth(login : String, password : String) : Result { + Log.e("getTokenNDSInAR", NetworkDataSource.auth(login, password).toString()) + return NetworkDataSource.auth(login, password) } suspend fun logout() { - codeCache = null + tokenCache = null App.context.userDataStore.edit { preferences -> - val prefKey = stringPreferencesKey(CODE_KEY) + val prefKey = stringPreferencesKey(TOKEN_KEY) preferences.remove(prefKey) } } diff --git a/app/src/main/java/ru/myitschool/work/data/repo/BookRepository.kt b/app/src/main/java/ru/myitschool/work/data/repo/BookRepository.kt index ea1c581..8aaa45d 100644 --- a/app/src/main/java/ru/myitschool/work/data/repo/BookRepository.kt +++ b/app/src/main/java/ru/myitschool/work/data/repo/BookRepository.kt @@ -1,5 +1,6 @@ package ru.myitschool.work.data.repo +import android.util.Log import ru.myitschool.work.data.dto.BookRequestDto import ru.myitschool.work.data.source.NetworkDataSource import ru.myitschool.work.domain.book.entities.BookRequestData @@ -10,8 +11,10 @@ class BookRepository( private val authRepository: AuthRepository ) { suspend fun getInfo(): Result { - val code = authRepository.getCode() ?: return getNoAuthResult() + val code = authRepository.auth() ?: return getNoAuthResult() + Log.e("getInfoCode", "!!!!!!!!!!!!!! getInfo ERROR $code") return NetworkDataSource.getInfo(code).mapCatching { dto -> + Log.e("getInfoCode", "!!!!!!!!!!!!!! getInfo ERROR ${dto.booking}") MainInfoEntity( name = dto.name ?: error("Name is null"), photoUrl = dto.photoUrl ?: error("Photo url is null"), @@ -26,7 +29,7 @@ class BookRepository( } suspend fun getBookingInfo(): Result> { - val code = authRepository.getCode() ?: return getNoAuthResult() + val code = authRepository.auth() ?: return getNoAuthResult() return NetworkDataSource.getBooking(code).mapCatching { dto -> dto?.map { (date, places) -> BookingData( @@ -43,7 +46,7 @@ class BookRepository( } suspend fun sendBook(data: BookRequestData): Result { - val code = authRepository.getCode() ?: return getNoAuthResult() + val code = authRepository.auth() ?: return getNoAuthResult() val dto = BookRequestDto(data.date, data.placeId) return NetworkDataSource.addBook(code, dto) } diff --git a/app/src/main/java/ru/myitschool/work/data/repo/MeetingsRepository.kt b/app/src/main/java/ru/myitschool/work/data/repo/MeetingsRepository.kt new file mode 100644 index 0000000..90ce6f5 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/data/repo/MeetingsRepository.kt @@ -0,0 +1,14 @@ +package ru.myitschool.work.data.repo + +import ru.myitschool.work.data.source.NetworkDataSource + +object MeetingsRepository { + private var roomCache: String? = null + + fun getRoom(): String? { + if (roomCache == null) { + NetworkDataSource + } + return roomCache + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt b/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt index 85387ac..b0f5055 100644 --- a/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt +++ b/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt @@ -1,5 +1,6 @@ package ru.myitschool.work.data.source +import android.util.Log import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.engine.cio.CIO @@ -35,10 +36,32 @@ object NetworkDataSource { } } } - - suspend fun checkAuth(code: String): Result = withContext(Dispatchers.IO) { + suspend fun auth(login: String, password: String): Result = withContext(Dispatchers.IO) { return@withContext runCatching { - val response = client.get(getUrl(code, Constants.AUTH_URL)) + val response = client.post("${Constants.HOST}/api${Constants.AUTH_URL}") { + contentType(ContentType.Application.Json) + setBody( + """{ + "login" : "$login", + "password" : "$password" + } """.trimIndent() + ) + } + Log.e("getTokenInNDS", response.body()) + if (response.status != HttpStatusCode.OK) { + Log.e("auth", response.status.toString()) + throw Exception("Неизвестная ошибка ${response.status}") + } + else if (response.status == HttpStatusCode.Unauthorized) { + throw Exception("Неверный логин или пароль") + } + response.body() + } + } + suspend fun checkAuth(token: String): Result = withContext(Dispatchers.IO) { + return@withContext runCatching { + Log.e("token", token) + val response = client.get(getUrl(token, Constants.AUTH_URL)) when (response.status) { HttpStatusCode.OK -> true else -> false @@ -46,23 +69,25 @@ object NetworkDataSource { } } - suspend fun getInfo(code: String): Result = withContext(Dispatchers.IO) { + suspend fun getInfo(token: String): Result = withContext(Dispatchers.IO) { return@withContext runCatching { - println("!!!!!!!!!!!!!! getInfo $code") - val response = client.get(getUrl(code, Constants.INFO_URL)) + println("!!!!!!!!!!!!!! getInfo $token") + val response = client.get(getUrl(token, Constants.INFO_URL)) if (response.status == HttpStatusCode.OK) { println("!!!!!!!!!!!!!! getInfo OK ${response.bodyAsText()}") + Log.d("1", "!!!!!!!!!!!!!! getInfo OK ${response.bodyAsText()}") response.body() } else { println("!!!!!!!!!!!!!! getInfo ERROR ${response.bodyAsText()}") + Log.e("getInfo", "!!!!!!!!!!!!!! getInfo ERROR ${response.bodyAsText()}") error(response.bodyAsText()) } } } - suspend fun getBooking(code: String): Result>?> = withContext(Dispatchers.IO) { + suspend fun getBooking(token: String): Result>?> = withContext(Dispatchers.IO) { return@withContext runCatching { - val response = client.get(getUrl(code, Constants.BOOKING_URL)) + val response = client.get(getUrl(token, Constants.BOOKING_URL)) if (response.status == HttpStatusCode.OK) { response.body>>() } else { @@ -71,9 +96,9 @@ object NetworkDataSource { } } - suspend fun addBook(code: String, data: BookRequestDto): Result = withContext(Dispatchers.IO) { + suspend fun addBook(token: String, data: BookRequestDto): Result = withContext(Dispatchers.IO) { return@withContext runCatching { - val response = client.post(getUrl(code, Constants.BOOK_URL)) { + val response = client.post(getUrl(token, Constants.BOOK_URL)) { contentType(ContentType.Application.Json) setBody(data) } @@ -85,5 +110,5 @@ object NetworkDataSource { } } - private fun getUrl(code: String, targetUrl: String) = "${Constants.HOST}/api/$code$targetUrl" + private fun getUrl(token: String, targetUrl: String) = "${Constants.HOST}/api/$targetUrl" } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/auth/CheckAndSaveAuthCodeUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/auth/CheckAndSaveAuthUseCase.kt similarity index 91% rename from app/src/main/java/ru/myitschool/work/domain/auth/CheckAndSaveAuthCodeUseCase.kt rename to app/src/main/java/ru/myitschool/work/domain/auth/CheckAndSaveAuthUseCase.kt index 012fb6f..460d80e 100644 --- a/app/src/main/java/ru/myitschool/work/domain/auth/CheckAndSaveAuthCodeUseCase.kt +++ b/app/src/main/java/ru/myitschool/work/domain/auth/CheckAndSaveAuthUseCase.kt @@ -2,7 +2,7 @@ package ru.myitschool.work.domain.auth import ru.myitschool.work.data.repo.AuthRepository -class CheckAndSaveAuthCodeUseCase( +class CheckAndSaveAuthUseCase( private val repository: AuthRepository ) { suspend operator fun invoke( diff --git a/app/src/main/java/ru/myitschool/work/domain/auth/CheckCodeFormatUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/auth/CheckCodeFormatUseCase.kt deleted file mode 100644 index fe291a0..0000000 --- a/app/src/main/java/ru/myitschool/work/domain/auth/CheckCodeFormatUseCase.kt +++ /dev/null @@ -1,12 +0,0 @@ -package ru.myitschool.work.domain.auth - -class CheckCodeFormatUseCase { - operator fun invoke( - text: String - ): Boolean { - return text.length == 4 && text.all { char -> - char.isLetterOrDigit() && - ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z') || char.isDigit()) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/auth/CheckLoginFormatUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/auth/CheckLoginFormatUseCase.kt new file mode 100644 index 0000000..f1ebfc3 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/auth/CheckLoginFormatUseCase.kt @@ -0,0 +1,9 @@ +package ru.myitschool.work.domain.auth + +class CheckLoginFormatUseCase { + operator fun invoke(login: String): Boolean { + return login.all { char -> char.isLetterOrDigit() && + ((char in 'A'..'Z') || (char in 'a'..'z') || char.isDigit()) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/auth/CheckPasswordFormatUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/auth/CheckPasswordFormatUseCase.kt new file mode 100644 index 0000000..2fc879d --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/auth/CheckPasswordFormatUseCase.kt @@ -0,0 +1,19 @@ +package ru.myitschool.work.domain.auth + +import kotlin.text.all + +class CheckPasswordFormatUseCase { + operator fun invoke( + password: String + ): Boolean { + return password.length >= 8 && password.all{char -> + (char in 'A'..'Z' || char in 'a'..'z' || char.isDigit()) || (char == '!' || char == '@' || + char == '#' || char == '$' || char == '&' || char == '*')} + } + fun validatePassword(password: String, login: String): Boolean { + val loginChars = login.lowercase().toSet() + return !password.lowercase().any{ + it in loginChars + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/auth/GetCodeUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/auth/GetTokenLocalUseCase.kt similarity index 75% rename from app/src/main/java/ru/myitschool/work/domain/auth/GetCodeUseCase.kt rename to app/src/main/java/ru/myitschool/work/domain/auth/GetTokenLocalUseCase.kt index a3c22b8..531303f 100644 --- a/app/src/main/java/ru/myitschool/work/domain/auth/GetCodeUseCase.kt +++ b/app/src/main/java/ru/myitschool/work/domain/auth/GetTokenLocalUseCase.kt @@ -2,10 +2,10 @@ package ru.myitschool.work.domain.auth import ru.myitschool.work.data.repo.AuthRepository -class GetCodeUseCase( +class GetTokenLocalUseCase( private val repository: AuthRepository ) { suspend operator fun invoke(): String? { - return repository.getCode() + return repository.auth() } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/auth/GetTokenNetworkUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/auth/GetTokenNetworkUseCase.kt new file mode 100644 index 0000000..6ada6b1 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/auth/GetTokenNetworkUseCase.kt @@ -0,0 +1,13 @@ +package ru.myitschool.work.domain.auth + +import android.util.Log +import ru.myitschool.work.data.repo.AuthRepository + +class GetTokenNetworkUseCase( + private val repository: AuthRepository +) { + suspend operator fun invoke(login : String, password: String): Result { + Log.e("GetTokenNetworkUseCase", repository.auth(login, password).toString()) + return repository.auth(login, password) + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/meetings/GetRoomUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/meetings/GetRoomUseCase.kt new file mode 100644 index 0000000..13d1e0d --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/meetings/GetRoomUseCase.kt @@ -0,0 +1,11 @@ +package ru.myitschool.work.domain.meetings + +import ru.myitschool.work.data.repo.MeetingsRepository + +class GetRoomUseCase ( + private val repository: MeetingsRepository +) { + suspend operator fun invoke(): String? { + return repository.getRoom() + } +} diff --git a/app/src/main/java/ru/myitschool/work/domain/meetings/MeetingsInfoEntity.kt b/app/src/main/java/ru/myitschool/work/domain/meetings/MeetingsInfoEntity.kt new file mode 100644 index 0000000..c31d118 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/meetings/MeetingsInfoEntity.kt @@ -0,0 +1,11 @@ +package ru.myitschool.work.domain.meetings + + +data class MeetingsInfoEntity( + val id: String, + val book: List +) { + data class Book( + val date: String + ) +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/custom/component/CustomButton.kt b/app/src/main/java/ru/myitschool/work/ui/custom/component/CustomButton.kt new file mode 100644 index 0000000..ddb7b86 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/custom/component/CustomButton.kt @@ -0,0 +1,64 @@ +package ru.myitschool.work.ui.custom.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.RoundRect +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import ru.myitschool.work.ui.theme.gray_gradient +import ru.myitschool.work.ui.theme.orange_gradient + +@Composable +fun CustomButon( + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + round : Dp = 10.dp, + content: @Composable RowScope.() -> Unit, +) { + Box( + modifier = modifier + .clickable { onClick() } + .background(if (enabled) orange_gradient else gray_gradient, RoundedCornerShape(round)) + + ) { + Row( + modifier = Modifier + .defaultMinSize( + minWidth = ButtonDefaults.MinWidth, + minHeight = ButtonDefaults.MinHeight, + ) + .fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + content = content, + ) + + } +} + +@Composable +fun RoundCustomButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + content: @Composable RowScope.() -> Unit, +) { + CustomButon( + onClick, modifier, enabled, content = content, + round = 50.dp + ) +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/nav/MeetingsScreenDestination.kt b/app/src/main/java/ru/myitschool/work/ui/nav/MeetingsScreenDestination.kt new file mode 100644 index 0000000..a61a2db --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/nav/MeetingsScreenDestination.kt @@ -0,0 +1,6 @@ +package ru.myitschool.work.ui.nav + +import kotlinx.serialization.Serializable + +@Serializable +data object MeetingsScreenDestination: AppDestination diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/NavigationGraph.kt b/app/src/main/java/ru/myitschool/work/ui/screen/NavigationGraph.kt index 3590d24..0afffd8 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/NavigationGraph.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/NavigationGraph.kt @@ -13,16 +13,18 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import kotlinx.coroutines.delay import ru.myitschool.work.data.repo.AuthRepository -import ru.myitschool.work.domain.auth.GetCodeUseCase +import ru.myitschool.work.domain.auth.GetTokenLocalUseCase +import ru.myitschool.work.domain.auth.GetTokenNetworkUseCase import ru.myitschool.work.ui.nav.AppDestination import ru.myitschool.work.ui.nav.AuthScreenDestination import ru.myitschool.work.ui.nav.BookScreenDestination import ru.myitschool.work.ui.nav.MainScreenDestination +import ru.myitschool.work.ui.nav.MeetingsScreenDestination import ru.myitschool.work.ui.screen.auth.AuthScreen import ru.myitschool.work.ui.screen.book.BookScreen import ru.myitschool.work.ui.screen.main.MainScreen +import ru.myitschool.work.ui.screen.meetings.MeetingsScreen @Composable fun AppNavHost( @@ -31,12 +33,13 @@ fun AppNavHost( ) { var destination by remember { mutableStateOf(null) } LaunchedEffect(Unit) { - val code = GetCodeUseCase(AuthRepository).invoke() - destination = if (code == null) { + val token = GetTokenLocalUseCase(AuthRepository).invoke() + destination = if (token == null) { AuthScreenDestination } else { MainScreenDestination } +// destination = MainScreenDestination } if (destination != null) { NavHost( @@ -55,6 +58,9 @@ fun AppNavHost( composable { BookScreen(navController = navController) } + composable { + MeetingsScreen() + } } } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt index 74f200a..b4aec57 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt @@ -1,6 +1,6 @@ package ru.myitschool.work.ui.screen.auth sealed interface AuthIntent { - data class Send(val text: String): AuthIntent - data class TextInput(val text: String): AuthIntent + data class Send(val login: String, val password: String): AuthIntent + data class TextInput(val login: String, val password: String): AuthIntent } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt index 4b91b98..dc4a26b 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt @@ -1,5 +1,6 @@ package ru.myitschool.work.ui.screen.auth +import android.util.Log import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -10,6 +11,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SecureTextField import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable @@ -24,12 +26,15 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController +import io.ktor.http.HttpStatusCode import ru.myitschool.work.R import ru.myitschool.work.core.TestIds +import ru.myitschool.work.ui.custom.component.CustomButon @Composable fun AuthScreen( @@ -47,7 +52,6 @@ fun AuthScreen( } } } - Column( modifier = Modifier .fillMaxSize() @@ -70,34 +74,56 @@ fun AuthScreen( } } } - +//@Composable +//fun SecureScreen(enabled: Boolean = true) { +// +//} @Composable private fun Content( viewModel: AuthViewModel, state: AuthState.Data ) { - var inputText by remember { mutableStateOf("") } + var inputTextLogin by remember { mutableStateOf("") } + var inputTextPassword by remember { mutableStateOf("") } Spacer(modifier = Modifier.size(16.dp)) TextField( - modifier = Modifier.testTag(TestIds.Auth.CODE_INPUT).fillMaxWidth(), - value = inputText, + modifier = Modifier.testTag(TestIds.Auth.LOGIN_INPUT).fillMaxWidth(), + value = inputTextLogin, onValueChange = { - inputText = it - viewModel.onIntent(AuthIntent.TextInput(it)) + inputTextLogin = it + viewModel.onIntent(AuthIntent.TextInput(inputTextLogin, inputTextPassword)) }, - label = { Text(stringResource(R.string.auth_label)) } + label = { Text(stringResource(R.string.auth_login)) } ) Spacer(modifier = Modifier.size(16.dp)) - Button( + TextField( + modifier = Modifier.testTag(TestIds.Auth.PASSWORD_INPUT).fillMaxWidth(), + value = inputTextPassword, + onValueChange = { + inputTextPassword = it + viewModel.onIntent(AuthIntent.TextInput(inputTextLogin, inputTextPassword)) + }, + label = { Text(stringResource(R.string.auth_password)) } + ) + Spacer(modifier = Modifier.size(16.dp)) + CustomButon( modifier = Modifier.testTag(TestIds.Auth.SIGN_BUTTON).fillMaxWidth(), onClick = { - viewModel.onIntent(AuthIntent.Send(inputText)) + viewModel.onIntent(AuthIntent.Send(inputTextLogin, inputTextPassword)) }, enabled = state.isEnabledSend ) { Text(stringResource(R.string.auth_sign_in)) } - if (state.error != null) { +// if (state.error != null) { +// Text( +// modifier = Modifier.testTag(TestIds.Auth.ERROR), +// text = state.error, +// style = MaterialTheme.typography.bodyMedium, +// color = Color.Red, +// ) +// } + if (state.error != null && !state.error.contains("401") && !state.error.contains("Network")) { Text( modifier = Modifier.testTag(TestIds.Auth.ERROR), text = state.error, @@ -105,4 +131,19 @@ private fun Content( color = Color.Red, ) } + if (state.error.toString().contains("401")) { + Text( + modifier = Modifier.testTag(TestIds.Auth.ERROR), + text = "Неверный логин или пароль", + style = MaterialTheme.typography.bodyMedium, + color = Color.Red, + ) + } else if (state.error.toString().contains("Network")) { + Text( + modifier = Modifier.testTag(TestIds.Auth.ERROR), + text = "Отсутствует интернет-соединение", + style = MaterialTheme.typography.bodyMedium, + color = Color.Red, + ) + } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt index c28f5cd..92fd117 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt @@ -1,5 +1,6 @@ package ru.myitschool.work.ui.screen.auth +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.MutableSharedFlow @@ -10,13 +11,15 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import ru.myitschool.work.data.repo.AuthRepository -import ru.myitschool.work.domain.auth.CheckAndSaveAuthCodeUseCase -import ru.myitschool.work.domain.auth.CheckCodeFormatUseCase +import ru.myitschool.work.domain.auth.CheckLoginFormatUseCase +import ru.myitschool.work.domain.auth.CheckPasswordFormatUseCase +import ru.myitschool.work.domain.auth.GetTokenNetworkUseCase import ru.myitschool.work.ui.nav.MainScreenDestination class AuthViewModel : ViewModel() { - private val checkCodeFormatUseCase by lazy { CheckCodeFormatUseCase() } - private val checkAndSaveAuthCodeUseCase by lazy { CheckAndSaveAuthCodeUseCase(AuthRepository) } + private val checkPasswordFormatUseCase by lazy { CheckPasswordFormatUseCase() } + private val checkLoginFormatUseCase by lazy { CheckLoginFormatUseCase() } + private val getTokenNetworkUseCase by lazy { GetTokenNetworkUseCase(AuthRepository) } private val _uiState = MutableStateFlow( AuthState.Data( isEnabledSend = false, @@ -27,12 +30,12 @@ class AuthViewModel : ViewModel() { private val _actionFlow: MutableSharedFlow = MutableSharedFlow() val actionFlow: SharedFlow = _actionFlow - fun onIntent(intent: AuthIntent) { when (intent) { is AuthIntent.Send -> { + Log.e("onIntent", intent.login) viewModelScope.launch { - checkAndSaveAuthCodeUseCase.invoke(intent.text).fold( + getTokenNetworkUseCase.invoke(intent.login, intent.password).fold( onSuccess = { _actionFlow.emit(AuthAction.Open(MainScreenDestination)) }, @@ -49,7 +52,7 @@ class AuthViewModel : ViewModel() { is AuthIntent.TextInput -> { updateStateIfData { oldState -> oldState.copy( - isEnabledSend = checkCodeFormatUseCase.invoke(intent.text), + isEnabledSend = checkLoginFormatUseCase.invoke(intent.login) && checkPasswordFormatUseCase.invoke(intent.password), error = null ) } diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/book/BookScreen.kt b/app/src/main/java/ru/myitschool/work/ui/screen/book/BookScreen.kt index 60842f3..1e8f7b4 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/book/BookScreen.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/book/BookScreen.kt @@ -141,6 +141,22 @@ private fun ErrorState( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { + when (state.error) { + "No auth" -> { + Image( + painter = painterResource(R.drawable.no_accounts), + null, + Modifier.size(100.dp) + ) + } + "Not internet" -> { + Image( + painter = painterResource(R.drawable.not_wifi), + null, + Modifier.size(100.dp) + ) + } + } Text( modifier = Modifier.testTag(TestIds.Book.ERROR), text = state.error, diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/main/MainScreen.kt b/app/src/main/java/ru/myitschool/work/ui/screen/main/MainScreen.kt index 19b9ff7..6ae6d18 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/main/MainScreen.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/main/MainScreen.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon @@ -30,11 +29,16 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.imageResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController @@ -42,6 +46,8 @@ import coil3.compose.AsyncImage import coil3.request.ImageRequest import ru.myitschool.work.R import ru.myitschool.work.core.TestIds +import ru.myitschool.work.ui.custom.component.CustomButon +import ru.myitschool.work.ui.custom.component.RoundCustomButton @Composable fun MainScreen( @@ -112,14 +118,30 @@ private fun ErrorState( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { + when (state.error) { + "No auth" -> { + Image( + painter = painterResource(R.drawable.no_accounts), + null, + Modifier.size(100.dp) + ) + } + "Not internet" -> { + Image( + painter = painterResource(R.drawable.not_wifi), + null, + Modifier.size(100.dp) + ) + } + } Text( modifier = Modifier.testTag(TestIds.Main.ERROR), text = state.error, style = MaterialTheme.typography.headlineSmall, - color = Color.Black, + color = Color.Red ) Spacer(modifier = Modifier.size(16.dp)) - Button( + RoundCustomButton( modifier = Modifier.testTag(TestIds.Main.REFRESH_BUTTON).fillMaxWidth(), onClick = { println("!!!!!!!! refresh on click error") @@ -229,4 +251,10 @@ private fun ContentState( ) } } +} + +@Preview +@Composable +fun Show() { +// MainScreen() } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/main/MainViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/screen/main/MainViewModel.kt index d04ec0b..006f35c 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/main/MainViewModel.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/main/MainViewModel.kt @@ -1,5 +1,6 @@ package ru.myitschool.work.ui.screen.main +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.collections.immutable.toPersistentList @@ -64,6 +65,7 @@ class MainViewModel : ViewModel() { _uiState.update { getMainDataUseCase.invoke().fold( onSuccess = { data -> + Log.d("DataMain", "${data.name}, ${data.book}") MainState.Data( name = data.name, photoUrl = data.photoUrl, diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingIntent.kt b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingIntent.kt new file mode 100644 index 0000000..83c58b3 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingIntent.kt @@ -0,0 +1,19 @@ +package ru.myitschool.work.ui.screen.meetings + +sealed interface MeetingIntent { + /** + * Обнавление страницы + */ + data object Refresh: MeetingIntent + /** + * Выход + */ + data object Logout: MeetingIntent + /** + * Бронирование + */ + data class Add( + val date: String, + val placeId: String + ): MeetingIntent +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingResult.kt b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingResult.kt new file mode 100644 index 0000000..b520f4c --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingResult.kt @@ -0,0 +1,5 @@ +package ru.myitschool.work.ui.screen.meetings + +object MeetingResult { + const val REFRESH_STATUS = "refresh_status" +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsAction.kt b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsAction.kt new file mode 100644 index 0000000..8affe18 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsAction.kt @@ -0,0 +1,10 @@ +package ru.myitschool.work.ui.screen.meetings + +import ru.myitschool.work.ui.nav.AppDestination + +sealed interface MeetingsAction { + class Open( + val destination: AppDestination, + val clearBackStack: Boolean = false + ): MeetingsAction +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsScreen.kt b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsScreen.kt new file mode 100644 index 0000000..b876fcd --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsScreen.kt @@ -0,0 +1,131 @@ +package ru.myitschool.work.ui.screen.meetings + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import ru.myitschool.work.R +import ru.myitschool.work.core.TestIds +import ru.myitschool.work.ui.custom.component.RoundCustomButton +import ru.myitschool.work.ui.screen.book.BookAction +import ru.myitschool.work.ui.screen.book.BookViewModel +import ru.myitschool.work.ui.screen.main.MainIntent +import ru.myitschool.work.ui.screen.main.MainResult + +@Composable +fun MeetingsScreen( + viewModel: MeetingsViewModel = viewModel() +) { + val state by viewModel.uiState.collectAsState() + + Column( + Modifier + .fillMaxSize() + ) { + when (val currentState = state) { + is MeetingsState.Data -> MeetingsData(currentState) + is MeetingsState.Empty -> MeetingsEmpty(currentState) + is MeetingsState.Error -> MeetingsError(viewModel, currentState) + is MeetingsState.Loading -> MeetingsLoading(currentState) + } + } +} + +@Composable +fun MeetingsData( + state: MeetingsState.Data +) { + +} + +@Composable +fun MeetingsEmpty( + state: MeetingsState.Empty +) { + Text( + modifier = Modifier.testTag(TestIds.Main.ERROR), + text = "Нет бронирований", + style = MaterialTheme.typography.headlineSmall, + color = Color.Red + ) +} + +@Composable +fun MeetingsError( + viewModel: MeetingsViewModel, + state: MeetingsState.Error +) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(all = 24.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + when (state.error) { + "No auth" -> { + Image( + painter = painterResource(R.drawable.no_accounts), + null, + Modifier.size(100.dp) + ) + } + "Not internet" -> { + Image( + painter = painterResource(R.drawable.not_wifi), + null, + Modifier.size(100.dp) + ) + } + } + Text( + modifier = Modifier.testTag(TestIds.Main.ERROR), + text = state.error, + style = MaterialTheme.typography.headlineSmall, + color = Color.Red + ) + Spacer(modifier = Modifier.size(16.dp)) + RoundCustomButton( + modifier = Modifier.testTag(TestIds.Main.REFRESH_BUTTON).fillMaxWidth(), + onClick = { + viewModel.refresh() + }, + ) { + Text(stringResource(R.string.main_refresh)) + } + } +} + +@Composable +fun MeetingsLoading( + state: MeetingsState.Loading +) { + Box( + Modifier.fillMaxWidth(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(64.dp) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsState.kt b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsState.kt new file mode 100644 index 0000000..b75ec26 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsState.kt @@ -0,0 +1,21 @@ +package ru.myitschool.work.ui.screen.meetings + +import kotlinx.collections.immutable.PersistentList + +sealed interface MeetingsState { + data object Loading: MeetingsState + data object Empty: MeetingsState + data class Error( + val error: String + ): MeetingsState + data class Data( + val name: String, + val books: PersistentList, + ): MeetingsState { + data class Book( + val date: String, + val time: String + ) + } +} + diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsViewModel.kt new file mode 100644 index 0000000..72fbe5b --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/screen/meetings/MeetingsViewModel.kt @@ -0,0 +1,73 @@ +package ru.myitschool.work.ui.screen.meetings + +import android.provider.Settings.System.DATE_FORMAT +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import ru.myitschool.work.data.repo.AuthRepository +import ru.myitschool.work.data.repo.BookRepository +import ru.myitschool.work.data.repo.MeetingsRepository +import ru.myitschool.work.domain.auth.LogoutUseCase +import ru.myitschool.work.domain.main.GetMainDataUseCase +import ru.myitschool.work.domain.meetings.GetRoomUseCase +import ru.myitschool.work.ui.nav.AuthScreenDestination +import ru.myitschool.work.ui.screen.main.MainAction +import ru.myitschool.work.ui.screen.main.MainState +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +class MeetingsViewModel: ViewModel() { + private val _uiState = MutableStateFlow(MeetingsState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + private val _actionFlow: MutableSharedFlow = MutableSharedFlow() + val actionFlow: SharedFlow = _actionFlow + private val logoutUseCase by lazy { + LogoutUseCase(AuthRepository) + } + private val getMeetingsDataUseCase by lazy { + GetRoomUseCase(MeetingsRepository) + } + init { + + } +// fun onIntent(intent: MeetingIntent) { +// when(intent) { +// is MeetingIntent.Logout -> { +// viewModelScope.launch { +// logoutUseCase.invoke() +// _actionFlow.emit(/*TODO*/) +// } +// } +// is MeetingIntent.Refresh -> { +// /*TODO("обновляться автоматически с заданной периодичностью")*/ +// } +// } +// } +// fun refresh() { +// viewModelScope.launch { +// _uiState.update { MeetingsState.Loading } +// _uiState.update { +// getMeetingsDataUseCase.invoke().fold( +// onFailure = { error -> +// MeetingsState.Error( +// error = error.message?.takeIf { it.isNotBlank() } ?: "Unknown error" +// ) +// }, +// onSuccess = { data -> +// MeetingsState.Data( +// name = data.name, +// books = data.book +// ) +// } +// ) +// } +// } +// } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/theme/Color.kt b/app/src/main/java/ru/myitschool/work/ui/theme/Color.kt index 22226f4..92c0a81 100644 --- a/app/src/main/java/ru/myitschool/work/ui/theme/Color.kt +++ b/app/src/main/java/ru/myitschool/work/ui/theme/Color.kt @@ -1,11 +1,20 @@ package ru.myitschool.work.ui.theme +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -val Purple80 = Color(0xFFD0BCFF) -val PurpleGrey80 = Color(0xFFCCC2DC) -val Pink80 = Color(0xFFEFB8C8) +val day_primary = Color(0xFFffa500) +val day_secondary = Color(0xFFffd700) +val day_tertiary = Color(0xFFffbe00) +val day_text = Color(0xFF003366) +val day_background = Color(0xFFf0f0f0) -val Purple40 = Color(0xFF6650a4) -val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file +val night_primary = Color(0xFFff8c00) +val night_secondary = Color(0xFFff7300) +val night_tertiary = Color(0xFFff5a00) +val night_text = Color(0xFFffe4b5) +val night_background = Color(0xFF121212) + + +val orange_gradient = Brush.linearGradient(listOf(day_primary, night_primary)) +val gray_gradient = Brush.linearGradient(listOf(Color(0xFFc4c7cf), Color(0xFF828897))) diff --git a/app/src/main/java/ru/myitschool/work/ui/theme/Font.kt b/app/src/main/java/ru/myitschool/work/ui/theme/Font.kt new file mode 100644 index 0000000..aae57bf --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/theme/Font.kt @@ -0,0 +1,26 @@ +package ru.myitschool.work.ui.theme + +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import ru.myitschool.work.R + +val subtitle = FontFamily( + Font( + R.font.merriweather_120pt_medium, + weight = FontWeight.Medium, + ) +) + +val title = FontFamily( + Font( + R.font.merriweather_120pt_bold, + weight = FontWeight.Bold + ) +) + +val normal = FontFamily( + Font( + R.font.roboto_serif_120pt_regular, + ) +) \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/theme/Theme.kt b/app/src/main/java/ru/myitschool/work/ui/theme/Theme.kt index d9cc58f..7e2b73d 100644 --- a/app/src/main/java/ru/myitschool/work/ui/theme/Theme.kt +++ b/app/src/main/java/ru/myitschool/work/ui/theme/Theme.kt @@ -11,15 +11,21 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalContext private val DarkColorScheme = darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 + primary = night_primary, + secondary = night_secondary, + tertiary = night_tertiary, + background = night_background, + onBackground = night_text, + onSurface = night_text, ) private val LightColorScheme = lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40, - tertiary = Pink40 + primary = day_primary, + secondary = day_secondary, + tertiary = day_tertiary, + background = day_background, + onBackground = day_text, + onSurface = day_text /* Other default colors to override background = Color(0xFFFFFBFE), @@ -36,7 +42,7 @@ private val LightColorScheme = lightColorScheme( fun WorkTheme( darkTheme: Boolean = isSystemInDarkTheme(), // Dynamic color is available on Android 12+ - dynamicColor: Boolean = true, + dynamicColor: Boolean = false, content: @Composable () -> Unit ) { val colorScheme = when { diff --git a/app/src/main/java/ru/myitschool/work/ui/theme/Type.kt b/app/src/main/java/ru/myitschool/work/ui/theme/Type.kt index 61b2923..4081ad5 100644 --- a/app/src/main/java/ru/myitschool/work/ui/theme/Type.kt +++ b/app/src/main/java/ru/myitschool/work/ui/theme/Type.kt @@ -9,26 +9,24 @@ import androidx.compose.ui.unit.sp // Set of Material typography styles to start with val Typography = Typography( bodyLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, + fontFamily = subtitle, + fontWeight = FontWeight.Medium, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.5.sp - ) - /* Other default text styles to override + ), titleLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, + fontFamily = title, + fontWeight = FontWeight.Bold, fontSize = 22.sp, lineHeight = 28.sp, letterSpacing = 0.sp ), labelSmall = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Medium, + fontFamily = normal, + fontWeight = FontWeight.Normal, fontSize = 11.sp, lineHeight = 16.sp, letterSpacing = 0.5.sp ) - */ ) \ No newline at end of file diff --git a/app/src/main/res/drawable/no_accounts.png b/app/src/main/res/drawable/no_accounts.png new file mode 100644 index 0000000..f42249a Binary files /dev/null and b/app/src/main/res/drawable/no_accounts.png differ diff --git a/app/src/main/res/drawable/not_auth.xml b/app/src/main/res/drawable/not_auth.xml new file mode 100644 index 0000000..361e4f0 --- /dev/null +++ b/app/src/main/res/drawable/not_auth.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/not_wifi.png b/app/src/main/res/drawable/not_wifi.png new file mode 100644 index 0000000..ec9d53a Binary files /dev/null and b/app/src/main/res/drawable/not_wifi.png differ diff --git a/app/src/main/res/font/merriweather_120pt_bold.ttf b/app/src/main/res/font/merriweather_120pt_bold.ttf new file mode 100644 index 0000000..69416ac Binary files /dev/null and b/app/src/main/res/font/merriweather_120pt_bold.ttf differ diff --git a/app/src/main/res/font/merriweather_120pt_medium.ttf b/app/src/main/res/font/merriweather_120pt_medium.ttf new file mode 100644 index 0000000..3a88e1b Binary files /dev/null and b/app/src/main/res/font/merriweather_120pt_medium.ttf differ diff --git a/app/src/main/res/font/roboto_serif_120pt_regular.ttf b/app/src/main/res/font/roboto_serif_120pt_regular.ttf new file mode 100644 index 0000000..d5dbfa6 Binary files /dev/null and b/app/src/main/res/font/roboto_serif_120pt_regular.ttf differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a9273cf..0e0eb8f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,8 +1,9 @@ Work RootActivity - Привет! Введи код для авторизации - Код + Привет! Введи свой логин и пароль для авторизации + Логин + Пароль Войти Обновить diff --git a/local.properties b/local.properties new file mode 100644 index 0000000..dcf330e --- /dev/null +++ b/local.properties @@ -0,0 +1,8 @@ +## This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Wed Feb 25 10:24:12 MSK 2026 +sdk.dir=C\:\\Users\\Samsung\\AppData\\Local\\Android\\Sdk