Search funcs
This commit is contained in:
Generated
+6
@@ -5,6 +5,12 @@
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="SearchTextFieldPrev">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="SearchContextMenuPrev">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
</project>
|
||||
@@ -6,13 +6,21 @@ import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import ru.megboyzz.lks.profile.ui.components.MainNavigator
|
||||
import ru.megboyzz.lks.profile.ui.screens.SearchScreen
|
||||
import ru.megboyzz.lks.profile.ui.screens.SignInScreen
|
||||
import ru.megboyzz.lks.profile.ui.theme.MainTheme
|
||||
|
||||
@@ -21,8 +29,9 @@ class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
|
||||
setContent {
|
||||
Navigator(SignInScreen())
|
||||
MainNavigator(SearchScreen())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,8 @@ class DataModule {
|
||||
fun providesDefaultCookies() = mapOf(
|
||||
"PHPSESSID" to "deleted",
|
||||
"BITRIX_SM_SOUND_LOGIN_PLAYED" to "Y",
|
||||
"BITRIX_SM_UIDH" to "00000000000000000000000000000000",
|
||||
"BITRIX_SM_UIDL" to "ivachev.a.a%40edu.mirea.ru"
|
||||
"BITRIX_SM_UIDH" to "22f459c5c83cff9cd62c99693b00c361",
|
||||
"BITRIX_SM_UIDL" to "kits.m.a%40edu.mirea.ru"
|
||||
)
|
||||
|
||||
}
|
||||
@@ -9,7 +9,9 @@ import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityComponent
|
||||
import dagger.multibindings.IntoMap
|
||||
import ru.megboyzz.lks.profile.ui.model.SearchScreenModel
|
||||
import ru.megboyzz.lks.profile.ui.model.SignInScreenModel
|
||||
import javax.inject.Qualifier
|
||||
|
||||
@Module
|
||||
@InstallIn(ActivityComponent::class)
|
||||
@@ -22,6 +24,9 @@ interface HiltModule {
|
||||
signInScreenModel: SignInScreenModel
|
||||
) : ScreenModel*/
|
||||
|
||||
@Qualifier
|
||||
annotation class MyFactory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ScreenModelFactoryKey(SignInScreenModel.Factory::class)
|
||||
@@ -29,4 +34,11 @@ interface HiltModule {
|
||||
factory: SignInScreenModel.Factory
|
||||
): ScreenModelFactory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ScreenModelKey(SearchScreenModel::class)
|
||||
fun bindSearchScreenModelFactory(
|
||||
factory: SearchScreenModel
|
||||
): ScreenModel
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package ru.megboyzz.lks.profile.ui
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
@Composable
|
||||
fun Modifier.clickableWithNormalRipple(onClick: () -> Unit) = this.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(bounded = true),
|
||||
onClick = onClick
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun Int.asPainter() = painterResource(this)
|
||||
@@ -0,0 +1,20 @@
|
||||
package ru.megboyzz.lks.profile.ui.components
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator
|
||||
import ru.megboyzz.lks.profile.ui.screens.SearchScreen
|
||||
|
||||
@Composable
|
||||
fun MainNavigator(screen: Screen) {
|
||||
BottomSheetNavigator(
|
||||
sheetShape = RoundedCornerShape(12.dp)
|
||||
) {
|
||||
|
||||
Navigator(screen)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
package ru.megboyzz.lks.profile.ui.components
|
||||
|
||||
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.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
|
||||
import ru.megboyzz.lks.profile.R
|
||||
import ru.megboyzz.lks.profile.domain.entities.LksRequest
|
||||
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
||||
import ru.megboyzz.lks.profile.domain.entities.Student
|
||||
import ru.megboyzz.lks.profile.ui.asPainter
|
||||
import ru.megboyzz.lks.profile.ui.clickableWithNormalRipple
|
||||
|
||||
@Composable
|
||||
fun ContextMenuContainer(
|
||||
content: @Composable ColumnScope.() -> Unit
|
||||
) {
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxWidth()
|
||||
.navigationBarsPadding(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(32.dp, 4.dp)
|
||||
.clip(RoundedCornerShape(80))
|
||||
.background(MaterialTheme.colorScheme.onBackground)
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Column (
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 12.dp)
|
||||
.padding(bottom = 12.dp),
|
||||
content = content
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ContextMenuContainerPrev() {
|
||||
|
||||
ContextMenuContainer {
|
||||
|
||||
Text("Hello!")
|
||||
Text("Hello!")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchTextField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
suggestions: List<String>? = null,
|
||||
label: String? = null
|
||||
) {
|
||||
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
var dropDownWidth by remember { mutableIntStateOf(0) }
|
||||
|
||||
val icon = if (expanded)
|
||||
Icons.Filled.KeyboardArrowUp
|
||||
else
|
||||
Icons.Filled.KeyboardArrowDown
|
||||
|
||||
|
||||
Column() {
|
||||
OutlinedTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.onSizeChanged { dropDownWidth = it.width },
|
||||
label = { Text(label ?: "Label") },
|
||||
trailingIcon = {
|
||||
if(suggestions != null)
|
||||
Icon(
|
||||
icon,
|
||||
"contentDescription",
|
||||
Modifier.clickableWithNormalRipple{ expanded = !expanded }
|
||||
)
|
||||
}
|
||||
)
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
modifier = Modifier
|
||||
.width(with(LocalDensity.current){dropDownWidth.toDp()})
|
||||
) {
|
||||
suggestions?.forEach { label ->
|
||||
DropdownMenuItem(
|
||||
onClick = { onValueChange(label) },
|
||||
text = { Text(text = label) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun SearchTextFieldPrev() {
|
||||
|
||||
val suggestions = listOf("Item1","Item2","Item3")
|
||||
var value by remember { mutableStateOf("") }
|
||||
|
||||
SearchTextField(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
suggestions = suggestions
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchContextMenu(
|
||||
onSearch: (LksRequest) -> Unit
|
||||
) {
|
||||
|
||||
val bottomSheetNavigator = LocalBottomSheetNavigator.current
|
||||
|
||||
var name by remember { mutableStateOf("") }
|
||||
var surname by remember { mutableStateOf("") }
|
||||
var family by remember { mutableStateOf("") }
|
||||
|
||||
var group by remember { mutableStateOf("") }
|
||||
var departamnet by remember { mutableStateOf("") }
|
||||
|
||||
ContextMenuContainer {
|
||||
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
|
||||
SearchTextField(
|
||||
value = family,
|
||||
onValueChange = {family = it},
|
||||
label = "Фамилия"
|
||||
)
|
||||
|
||||
SearchTextField(
|
||||
value = name,
|
||||
onValueChange = {name = it},
|
||||
label = "Имя"
|
||||
)
|
||||
|
||||
SearchTextField(
|
||||
value = surname,
|
||||
onValueChange = {surname = it},
|
||||
label = "Отчество"
|
||||
)
|
||||
|
||||
Spacer(Modifier.height(1.dp))
|
||||
HorizontalDivider(color = MaterialTheme.colorScheme.onBackground)
|
||||
|
||||
SearchTextField(
|
||||
value = group,
|
||||
onValueChange = {group = it},
|
||||
label = "Учебная группа"
|
||||
)
|
||||
|
||||
SearchTextField(
|
||||
value = departamnet,
|
||||
onValueChange = { departamnet = it },
|
||||
label = "Подразделение"
|
||||
)
|
||||
|
||||
Button(
|
||||
shape = OutlinedTextFieldDefaults.shape,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
val lksRequest = LksRequest(
|
||||
student = Student(
|
||||
name = name,
|
||||
surname = family,
|
||||
patronymic = surname
|
||||
),
|
||||
group = group,
|
||||
department = departamnet
|
||||
)
|
||||
onSearch(lksRequest)
|
||||
bottomSheetNavigator?.hide()
|
||||
}
|
||||
) {
|
||||
Text("Поиск")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun SearchContextMenuPrev() {
|
||||
|
||||
SearchContextMenu {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ContextMenuButton(
|
||||
icon: Painter,
|
||||
label: String,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.clickableWithNormalRipple(onClick)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = icon,
|
||||
contentDescription = null
|
||||
)
|
||||
Text(text = label)
|
||||
}
|
||||
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
|
||||
contentDescription = null
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ContextMenuButtonPrev() {
|
||||
|
||||
ContextMenuButton(
|
||||
icon = R.drawable.vk_ic.asPainter(),
|
||||
label = "Переидти в VK",
|
||||
onClick = {}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LongPressCardContextMenu(
|
||||
lksStudent: LksStudent,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
ContextMenuContainer {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
|
||||
Text(
|
||||
"${lksStudent.studentFullName} ${lksStudent.group}"
|
||||
)
|
||||
HorizontalDivider(color = MaterialTheme.colorScheme.onBackground)
|
||||
ContextMenuButton(
|
||||
icon = R.drawable.vk_ic.asPainter(),
|
||||
label = "Переидти в VK",
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun LongPressCardContextMenuPrev() {
|
||||
|
||||
val lksStudent = LksStudent(
|
||||
studentFullName = "Киц Михаил Андреевич",
|
||||
group = "ИКБО-03-20"
|
||||
)
|
||||
|
||||
LongPressCardContextMenu(
|
||||
lksStudent = lksStudent,
|
||||
onClick = {}
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,166 @@
|
||||
package ru.megboyzz.lks.profile.ui.components
|
||||
|
||||
import android.provider.ContactsContract.Profile
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ru.megboyzz.lks.profile.MainActivity
|
||||
import ru.megboyzz.lks.profile.domain.entities.LksResponse
|
||||
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
||||
import ru.megboyzz.lks.profile.ui.clickableWithNormalRipple
|
||||
import ru.megboyzz.lks.profile.ui.theme.MainTheme
|
||||
|
||||
@Composable
|
||||
fun ProfileCard(lksStudent: LksStudent) {
|
||||
fun ProfileCard(
|
||||
lksStudent: LksStudent,
|
||||
onLongPress: () -> Unit
|
||||
) {
|
||||
|
||||
var toggled by remember { mutableStateOf(false) }
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.border(
|
||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
.defaultMinSize(minWidth = 240.dp)
|
||||
.clickableWithNormalRipple { toggled =! toggled },
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().padding(12.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = lksStudent.studentFullName ?: "<Нет имени>"
|
||||
)
|
||||
Text(
|
||||
text = lksStudent.group ?: "<Нет группы>"
|
||||
)
|
||||
AnimatedVisibility(toggled) {
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(top = 4.dp).fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Text(
|
||||
text = lksStudent.department ?: "<Нет подразделения>"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MainScaffold(
|
||||
onFloatingButtonClick: () -> Unit,
|
||||
content: @Composable (PaddingValues) -> Unit
|
||||
) {
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
Surface(shadowElevation = 8.dp) {
|
||||
TopAppBar(
|
||||
title = { Text("LKS Search") }
|
||||
)
|
||||
}
|
||||
},
|
||||
floatingActionButton = {
|
||||
FloatingActionButton(onFloatingButtonClick) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Search,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
},
|
||||
content = content
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ProfileCardPrev() {
|
||||
|
||||
val student = LksStudent(
|
||||
studentFullName = "Киц Михаил Андреевич",
|
||||
department = "ИИТ",
|
||||
group = "ИКБО-03-20"
|
||||
)
|
||||
|
||||
ProfileCard(
|
||||
lksStudent = student
|
||||
) { }
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Main() {
|
||||
|
||||
val student = LksStudent(
|
||||
studentFullName = "Киц Михаил Андреевич",
|
||||
department = "ИИТ",
|
||||
group = "ИКБО-03-20"
|
||||
)
|
||||
|
||||
MainTheme {
|
||||
MainScaffold(
|
||||
onFloatingButtonClick = {}
|
||||
) {
|
||||
Column(modifier = Modifier.padding(it)) {
|
||||
ProfileCard(
|
||||
lksStudent = student
|
||||
) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,14 +2,19 @@ package ru.megboyzz.lks.profile.ui.model
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import cafe.adriel.voyager.hilt.ScreenModelFactory
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import dagger.assisted.AssistedFactory
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.megboyzz.lks.profile.domain.DefaultCookies
|
||||
import ru.megboyzz.lks.profile.domain.entities.LksRequest
|
||||
import ru.megboyzz.lks.profile.domain.entities.LksResponse
|
||||
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
|
||||
import ru.megboyzz.lks.profile.ui.HiltModule.MyFactory
|
||||
import javax.inject.Inject
|
||||
|
||||
class SearchScreenModel @Inject constructor(
|
||||
@@ -27,30 +32,49 @@ class SearchScreenModel @Inject constructor(
|
||||
private val _responseList = MutableStateFlow(LksResponse())
|
||||
val responseList = _responseList.asStateFlow()
|
||||
|
||||
sealed class UiState(val status: String? = null) {
|
||||
data object Loading: UiState()
|
||||
//data object Success: SignInState("Успешный вход")
|
||||
data class Error(val _status: String) : UiState(_status)
|
||||
data object Idle: UiState()
|
||||
}
|
||||
|
||||
val state = MutableStateFlow<UiState>(UiState.Idle)
|
||||
|
||||
init {
|
||||
_curPageNumber.onEach {
|
||||
/* _curPageNumber.onEach {
|
||||
update()
|
||||
}
|
||||
}*/
|
||||
|
||||
_request.onEach {
|
||||
update()
|
||||
}.launchIn(screenModelScope)
|
||||
|
||||
}
|
||||
|
||||
fun nextPage() = screenModelScope.launch { _curPageNumber.emit(_curPageNumber.value++) }
|
||||
|
||||
private fun update() = screenModelScope.launch {
|
||||
|
||||
state.emit(UiState.Loading)
|
||||
|
||||
val result = lksRepository.getPage(_request.value, cookies, curPageNumber.value)
|
||||
|
||||
if(result.isFailure) {
|
||||
state.emit(UiState.Error("Ошибка :-("))
|
||||
return@launch
|
||||
}
|
||||
|
||||
val list = result.getOrElse { LksResponse() }
|
||||
|
||||
_responseList.emit(list)
|
||||
|
||||
state.emit(UiState.Idle)
|
||||
}
|
||||
|
||||
fun newSearch() = screenModelScope.launch {
|
||||
|
||||
_curPageNumber.emit(1)
|
||||
update()
|
||||
|
||||
fun newSearch(request: LksRequest) = screenModelScope.launch {
|
||||
_request.emit(request)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,44 +1,58 @@
|
||||
package ru.megboyzz.lks.profile.ui.screens
|
||||
|
||||
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.height
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.input.pointer.PointerIcon.Companion.Text
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.hilt.getScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
|
||||
import ru.megboyzz.lks.profile.ui.components.MainScaffold
|
||||
import ru.megboyzz.lks.profile.ui.components.ProfileCard
|
||||
import ru.megboyzz.lks.profile.ui.model.SearchScreenModel
|
||||
import ru.megboyzz.lks.profile.ui.screens.sub.LongPressMenu
|
||||
import ru.megboyzz.lks.profile.ui.screens.sub.SearchBottomScreen
|
||||
|
||||
class SearchScreen : Screen {
|
||||
@Composable
|
||||
override fun Content() {
|
||||
|
||||
val bottomSheetNavigator = LocalBottomSheetNavigator.current
|
||||
|
||||
val screenModel = getScreenModel<SearchScreenModel>()
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.TopCenter
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
val list by screenModel.responseList.collectAsState()
|
||||
|
||||
MainScaffold(
|
||||
onFloatingButtonClick = { bottomSheetNavigator.show(SearchBottomScreen()) }
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(8.dp)
|
||||
) {
|
||||
Spacer(Modifier.height(20.dp))
|
||||
val navigator = LocalNavigator.current!!
|
||||
|
||||
|
||||
|
||||
|
||||
item {
|
||||
when(state) {
|
||||
is SearchScreenModel.UiState.Loading -> CircularProgressIndicator()
|
||||
is SearchScreenModel.UiState.Error -> Text(state.status ?: "Ошибка")
|
||||
SearchScreenModel.UiState.Idle -> {}
|
||||
}
|
||||
}
|
||||
items(list.students) {
|
||||
ProfileCard(
|
||||
lksStudent = it,
|
||||
onLongPress = { bottomSheetNavigator.show(LongPressMenu(it)) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package ru.megboyzz.lks.profile.ui.screens.sub
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
||||
import ru.megboyzz.lks.profile.ui.components.LongPressCardContextMenu
|
||||
|
||||
class LongPressMenu(private val lksStudent: LksStudent) : Screen {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
LongPressCardContextMenu(
|
||||
lksStudent = lksStudent
|
||||
) {
|
||||
Toast.makeText(context, "Переход на VK", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package ru.megboyzz.lks.profile.ui.screens.sub
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.hilt.getScreenModel
|
||||
import ru.megboyzz.lks.profile.ui.components.SearchContextMenu
|
||||
import ru.megboyzz.lks.profile.ui.model.SearchScreenModel
|
||||
|
||||
class SearchBottomScreen : Screen {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
|
||||
val screenModel = getScreenModel<SearchScreenModel>()
|
||||
|
||||
SearchContextMenu { lksRequest -> screenModel.newSearch(lksRequest) }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
@@ -19,9 +20,9 @@ private val DarkColorScheme = darkColorScheme(
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Purple40,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
tertiary = Pink40,
|
||||
|
||||
/* Other default colors to override
|
||||
// Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
@@ -29,7 +30,7 @@ private val LightColorScheme = lightColorScheme(
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -14,11 +14,11 @@ val Typography = Typography(
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
),
|
||||
// Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
@@ -30,5 +30,4 @@ val Typography = Typography(
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M42,37c0,2.762 -2.238,5 -5,5H11c-2.761,0 -5,-2.238 -5,-5V11c0,-2.762 2.239,-5 5,-5h26c2.762,0 5,2.238 5,5V37z"
|
||||
android:fillColor="#1976d2"/>
|
||||
<path
|
||||
android:pathData="M35.937,18.041c0.046,-0.151 0.068,-0.291 0.062,-0.416C35.984,17.263 35.735,17 35.149,17h-2.618c-0.661,0 -0.966,0.4 -1.144,0.801c0,0 -1.632,3.359 -3.513,5.574c-0.61,0.641 -0.92,0.625 -1.25,0.625C26.447,24 26,23.786 26,23.199v-5.185C26,17.32 25.827,17 25.268,17h-4.649C20.212,17 20,17.32 20,17.641c0,0.667 0.898,0.827 1,2.696v3.623C21,24.84 20.847,25 20.517,25c-0.89,0 -2.642,-3 -3.815,-6.932C16.448,17.294 16.194,17 15.533,17h-2.643C12.127,17 12,17.374 12,17.774c0,0.721 0.6,4.619 3.875,9.101C18.25,30.125 21.379,32 24.149,32c1.678,0 1.85,-0.427 1.85,-1.094v-2.972C26,27.133 26.183,27 26.717,27c0.381,0 1.158,0.25 2.658,2c1.73,2.018 2.044,3 3.036,3h2.618c0.608,0 0.957,-0.255 0.971,-0.75c0.003,-0.126 -0.015,-0.267 -0.056,-0.424c-0.194,-0.576 -1.084,-1.984 -2.194,-3.326c-0.615,-0.743 -1.222,-1.479 -1.501,-1.879C32.062,25.36 31.991,25.176 32,25c0.009,-0.185 0.105,-0.361 0.249,-0.607C32.223,24.393 35.607,19.642 35.937,18.041z"
|
||||
android:fillColor="#fff"/>
|
||||
</vector>
|
||||
Reference in New Issue
Block a user