Checkpoint 3.ui.1
This commit is contained in:
parent
2ef8b4a307
commit
3c2d359a01
@ -0,0 +1,9 @@
|
||||
package ru.myitschool.work.data.repo
|
||||
|
||||
object MeetingsRepository {
|
||||
private var roomCache: String? = null
|
||||
|
||||
fun getRoom(): String? {
|
||||
return roomCache
|
||||
}
|
||||
}
|
||||
@ -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 in 'A'..'Z') || (char >= 'a' && char <= 'z') || char.isDigit())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package ru.myitschool.work.ui.nav
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data object MeetingsScreenDestination: AppDestination
|
||||
@ -20,9 +20,11 @@ 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(
|
||||
@ -37,6 +39,7 @@ fun AppNavHost(
|
||||
} else {
|
||||
MainScreenDestination
|
||||
}
|
||||
// destination = MainScreenDestination
|
||||
}
|
||||
if (destination != null) {
|
||||
NavHost(
|
||||
@ -55,6 +58,9 @@ fun AppNavHost(
|
||||
composable<BookScreenDestination> {
|
||||
BookScreen(navController = navController)
|
||||
}
|
||||
composable<MeetingsScreenDestination> {
|
||||
MeetingsScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -31,6 +31,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import ru.myitschool.work.R
|
||||
import ru.myitschool.work.core.TestIds
|
||||
import ru.myitschool.work.ui.custom.component.CustomButon
|
||||
|
||||
@Composable
|
||||
fun AuthScreen(
|
||||
@ -102,7 +103,7 @@ private fun Content(
|
||||
label = { Text(stringResource(R.string.auth_password)) }
|
||||
)
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
Button(
|
||||
CustomButon(
|
||||
modifier = Modifier.testTag(TestIds.Auth.SIGN_BUTTON).fillMaxWidth(),
|
||||
onClick = {
|
||||
viewModel.onIntent(AuthIntent.Send(inputTextLogin, inputTextPassword))
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,9 +29,13 @@ 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
|
||||
@ -43,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(
|
||||
@ -113,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")
|
||||
|
||||
@ -1,8 +1,17 @@
|
||||
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
|
||||
|
||||
@ -1,4 +1,62 @@
|
||||
package ru.myitschool.work.ui.screen.meetings
|
||||
|
||||
class MeetingsScreen {
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
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.Modifier
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import ru.myitschool.work.ui.screen.book.BookAction
|
||||
import ru.myitschool.work.ui.screen.book.BookViewModel
|
||||
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 -> TODO()
|
||||
is MeetingsState.Loading -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MeetingsData(
|
||||
state: MeetingsState.Data
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MeetingsEmpty(
|
||||
state: MeetingsState.Empty
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MeetingsError(
|
||||
state: MeetingsState.Error
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MeetingsLoading(
|
||||
state: MeetingsState.Loading
|
||||
) {
|
||||
|
||||
}
|
||||
@ -9,22 +9,11 @@ sealed interface MeetingsState {
|
||||
val error: String
|
||||
): MeetingsState
|
||||
data class Data(
|
||||
val name: String,
|
||||
val photoUrl: String,
|
||||
val books: PersistentList<Book>,
|
||||
val items: PersistentList<Item>
|
||||
): MeetingsState {
|
||||
data class Book(
|
||||
val date: String,
|
||||
val place: String,
|
||||
)
|
||||
data class Item(
|
||||
val date: String,
|
||||
val places: PersistentList<Place>,
|
||||
)
|
||||
data class Place(
|
||||
val id: String,
|
||||
val name: String,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,18 @@
|
||||
package ru.myitschool.work.ui.screen.meetings
|
||||
|
||||
class MeetingsViewModel {
|
||||
import androidx.lifecycle.ViewModel
|
||||
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
|
||||
|
||||
class MeetingsViewModel : ViewModel() {
|
||||
private val _uiState = MutableStateFlow<MeetingsState>(MeetingsState.Loading)
|
||||
val uiState: StateFlow<MeetingsState> = _uiState.asStateFlow()
|
||||
|
||||
private val _actionFlow: MutableSharedFlow<MeetingsAction> = MutableSharedFlow()
|
||||
val actionFlow: SharedFlow<MeetingsAction> = _actionFlow
|
||||
|
||||
|
||||
}
|
||||
@ -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)
|
||||
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)))
|
||||
|
||||
26
app/src/main/java/ru/myitschool/work/ui/theme/Font.kt
Normal file
26
app/src/main/java/ru/myitschool/work/ui/theme/Font.kt
Normal file
@ -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,
|
||||
)
|
||||
)
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
)
|
||||
*/
|
||||
)
|
||||
BIN
app/src/main/res/drawable/no_accounts.png
Normal file
BIN
app/src/main/res/drawable/no_accounts.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
52
app/src/main/res/drawable/not_auth.xml
Normal file
52
app/src/main/res/drawable/not_auth.xml
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 37 KiB |
BIN
app/src/main/res/drawable/not_wifi.png
Normal file
BIN
app/src/main/res/drawable/not_wifi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
BIN
app/src/main/res/font/merriweather_120pt_bold.ttf
Normal file
BIN
app/src/main/res/font/merriweather_120pt_bold.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/merriweather_120pt_medium.ttf
Normal file
BIN
app/src/main/res/font/merriweather_120pt_medium.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/roboto_serif_120pt_regular.ttf
Normal file
BIN
app/src/main/res/font/roboto_serif_120pt_regular.ttf
Normal file
Binary file not shown.
@ -4,5 +4,5 @@
|
||||
# Location of the SDK. This is only used by Gradle.
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
#Tue Feb 24 18:06:36 MSK 2026
|
||||
#Wed Feb 25 10:24:12 MSK 2026
|
||||
sdk.dir=C\:\\Users\\Samsung\\AppData\\Local\\Android\\Sdk
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user