filany refactor code
This commit is contained in:
@@ -2,6 +2,7 @@ plugins {
|
|||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
alias(libs.plugins.kotlin.compose)
|
alias(libs.plugins.kotlin.compose)
|
||||||
|
alias(libs.plugins.kotlin.serialization)
|
||||||
id("com.google.devtools.ksp")
|
id("com.google.devtools.ksp")
|
||||||
id("com.google.dagger.hilt.android")
|
id("com.google.dagger.hilt.android")
|
||||||
}
|
}
|
||||||
@@ -59,10 +60,14 @@ dependencies {
|
|||||||
debugImplementation(libs.androidx.ui.tooling)
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
debugImplementation(libs.androidx.ui.test.manifest)
|
||||||
|
|
||||||
|
implementation(libs.androidx.room.ktx)
|
||||||
|
implementation(libs.androidx.room.runtime)
|
||||||
|
|
||||||
|
implementation(libs.navigation.compose)
|
||||||
implementation(libs.hilt.android)
|
implementation(libs.hilt.android)
|
||||||
ksp(libs.hilt.android.compiler)
|
ksp(libs.hilt.android.compiler)
|
||||||
|
ksp(libs.androidx.room.compiler)
|
||||||
|
|
||||||
|
|
||||||
implementation(libs.jsoup)
|
implementation(libs.jsoup)
|
||||||
|
implementation(libs.kotlinx.serialization.json)
|
||||||
}
|
}
|
||||||
@@ -4,22 +4,9 @@ import android.os.Bundle
|
|||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
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 dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import ru.megboyzz.lks.profile.ui.components.MainNavigator
|
import ru.megboyzz.lks.profile.ui.components.MainNavHost
|
||||||
import ru.megboyzz.lks.profile.ui.screens.SearchScreen
|
import ru.megboyzz.lks.profile.ui.provider.ActivityProvider
|
||||||
import ru.megboyzz.lks.profile.ui.screens.SignInScreen
|
|
||||||
import ru.megboyzz.lks.profile.ui.theme.MainTheme
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
@@ -29,7 +16,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
MainNavigator(SignInScreen())
|
MainNavHost()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ import kotlinx.coroutines.withContext
|
|||||||
import org.jsoup.Connection
|
import org.jsoup.Connection
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
|
import ru.megboyzz.lks.profile.domain.entities.LksResponse
|
||||||
|
|
||||||
private typealias Cookies = Map<String, String>
|
private typealias Cookies = Map<String, String>
|
||||||
|
|
||||||
@@ -65,9 +66,9 @@ fun Document.getTotalPages() = kotlin.runCatching {
|
|||||||
this.select("body > div.container > div.bx-pagination > div > ul > li:nth-child(6) > a > span").text().toInt()
|
this.select("body > div.container > div.bx-pagination > div > ul > li:nth-child(6) > a > span").text().toInt()
|
||||||
}.getOrNull() ?: 0
|
}.getOrNull() ?: 0
|
||||||
|
|
||||||
fun findStudentsInPage(document: Document): LksStudent {
|
fun findStudentsInPage(document: Document): LksResponse {
|
||||||
|
|
||||||
val table = document.select("body > div.container > table > tbody") ?: return LksStudent()
|
val table = document.select("body > div.container > table > tbody") ?: return LksResponse()
|
||||||
|
|
||||||
val students = table.select("tr").map {
|
val students = table.select("tr").map {
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ fun findStudentsInPage(document: Document): LksStudent {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return LksStudent(
|
return LksResponse(
|
||||||
students = students,
|
students = students,
|
||||||
availablePages = document.getTotalPages()
|
availablePages = document.getTotalPages()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import ru.megboyzz.lks.profile.data.getProfilePage
|
|||||||
import ru.megboyzz.lks.profile.data.signInLks
|
import ru.megboyzz.lks.profile.data.signInLks
|
||||||
import ru.megboyzz.lks.profile.domain.CookiesPrefs
|
import ru.megboyzz.lks.profile.domain.CookiesPrefs
|
||||||
import ru.megboyzz.lks.profile.domain.entities.LksRequest
|
import ru.megboyzz.lks.profile.domain.entities.LksRequest
|
||||||
|
import ru.megboyzz.lks.profile.domain.entities.LksResponse
|
||||||
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
||||||
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
|
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -57,7 +58,7 @@ class LksRepositoryImpl @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getPage(lksRequest: LksRequest, cookie: Map<String, String>, pageNumber: Int): Result<LksStudent> {
|
override suspend fun getPage(lksRequest: LksRequest, cookie: Map<String, String>, pageNumber: Int): Result<LksResponse> {
|
||||||
|
|
||||||
Log.i("TEXT", "Its begin doc!")
|
Log.i("TEXT", "Its begin doc!")
|
||||||
val document = getProfilePage(lksRequest, cookie, pageNumber)
|
val document = getProfilePage(lksRequest, cookie, pageNumber)
|
||||||
@@ -67,7 +68,7 @@ class LksRepositoryImpl @Inject constructor(
|
|||||||
val page = findStudentsInPage(document)
|
val page = findStudentsInPage(document)
|
||||||
Log.i("TEXT", "Its end!")
|
Log.i("TEXT", "Its end!")
|
||||||
|
|
||||||
return if(page == LksStudent())
|
return if(page == LksResponse())
|
||||||
Result.failure(Exception())
|
Result.failure(Exception())
|
||||||
else
|
else
|
||||||
Result.success(page)
|
Result.success(page)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package ru.megboyzz.lks.profile.domain.entities
|
package ru.megboyzz.lks.profile.domain.entities
|
||||||
|
|
||||||
data class LksStudent(
|
data class LksResponse(
|
||||||
val students: List<LksStudent> = emptyList(),
|
val students: List<LksStudent> = emptyList(),
|
||||||
val availablePages: Int = 0
|
val availablePages: Int = 0
|
||||||
)
|
)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package ru.megboyzz.lks.profile.domain.repositories
|
package ru.megboyzz.lks.profile.domain.repositories
|
||||||
|
|
||||||
import ru.megboyzz.lks.profile.domain.entities.LksRequest
|
import ru.megboyzz.lks.profile.domain.entities.LksRequest
|
||||||
|
import ru.megboyzz.lks.profile.domain.entities.LksResponse
|
||||||
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ interface LksRepository: Serializable {
|
|||||||
|
|
||||||
suspend fun cookiesIsValid(cookie: Map<String, String>): Boolean
|
suspend fun cookiesIsValid(cookie: Map<String, String>): Boolean
|
||||||
|
|
||||||
suspend fun getPage(lksRequest: LksRequest, cookie: Map<String, String>, pageNumber: Int): Result<LksStudent>
|
suspend fun getPage(lksRequest: LksRequest, cookie: Map<String, String>, pageNumber: Int): Result<LksResponse>
|
||||||
|
|
||||||
fun saveCookie(cookie: Map<String, String>)
|
fun saveCookie(cookie: Map<String, String>)
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
package ru.megboyzz.lks.profile.ui
|
|
||||||
|
|
||||||
import cafe.adriel.voyager.core.model.ScreenModel
|
|
||||||
import cafe.adriel.voyager.hilt.ScreenModelFactory
|
|
||||||
import cafe.adriel.voyager.hilt.ScreenModelFactoryKey
|
|
||||||
import cafe.adriel.voyager.hilt.ScreenModelKey
|
|
||||||
import dagger.Binds
|
|
||||||
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)
|
|
||||||
interface HiltModule {
|
|
||||||
|
|
||||||
/*@Binds
|
|
||||||
@IntoMap
|
|
||||||
@ScreenModelKey(SignInScreenModel::class)
|
|
||||||
abstract fun bindSignInScreenModel(
|
|
||||||
signInScreenModel: SignInScreenModel
|
|
||||||
) : ScreenModel*/
|
|
||||||
|
|
||||||
@Qualifier
|
|
||||||
annotation class MyFactory
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@ScreenModelFactoryKey(SignInScreenModel.Factory::class)
|
|
||||||
fun bindSignInScreenModelFactory(
|
|
||||||
factory: SignInScreenModel.Factory
|
|
||||||
): ScreenModelFactory
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@ScreenModelKey(SearchScreenModel::class)
|
|
||||||
fun bindSearchScreenModelFactory(
|
|
||||||
factory: SearchScreenModel
|
|
||||||
): ScreenModel
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,8 @@ package ru.megboyzz.lks.profile.ui
|
|||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
@@ -51,4 +53,12 @@ fun Context.copyToClipboard(content: String) {
|
|||||||
clipboardManager.setPrimaryClip(clip)
|
clipboardManager.setPrimaryClip(clip)
|
||||||
|
|
||||||
Toast.makeText(this, "Текст скопирован в буфер обмена", Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, "Текст скопирован в буфер обмена", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.goToVK(request: String) {
|
||||||
|
val browserIntent = Intent(
|
||||||
|
Intent.ACTION_VIEW,
|
||||||
|
Uri.parse("https://vk.com/search?q=$request")
|
||||||
|
)
|
||||||
|
this.startActivity(browserIntent)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package ru.megboyzz.lks.profile.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
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.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SimpleDropdownMenu(
|
||||||
|
expanded: Boolean,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
content: @Composable ColumnScope.() -> Unit
|
||||||
|
) = DropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SimpleDropdownMenuItem(
|
||||||
|
text: String,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) = DropdownMenuItem(
|
||||||
|
text = { Text(text) },
|
||||||
|
onClick = onClick
|
||||||
|
)
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package ru.megboyzz.lks.profile.ui.components
|
||||||
|
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.navigation.compose.NavHost
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.Serializer
|
||||||
|
import ru.megboyzz.lks.profile.ui.model.SignInViewModel
|
||||||
|
import ru.megboyzz.lks.profile.ui.provider.ActivityProvider
|
||||||
|
import ru.megboyzz.lks.profile.ui.provider.LocalMainActivity
|
||||||
|
import ru.megboyzz.lks.profile.ui.screens.SearchScreenContent
|
||||||
|
import ru.megboyzz.lks.profile.ui.screens.SignInScreenContent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Место где лучше всего применять все CompositionProvider
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MainNavHost() = ActivityProvider {
|
||||||
|
|
||||||
|
val navHostController = rememberNavController()
|
||||||
|
|
||||||
|
val viewModel by LocalMainActivity.current.viewModels<SignInViewModel>()
|
||||||
|
|
||||||
|
val state by viewModel.state.collectAsState()
|
||||||
|
|
||||||
|
if(state is SignInViewModel.SignInState.Success) {
|
||||||
|
navHostController.navigate(SearchScreen)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavHost(
|
||||||
|
navController = navHostController,
|
||||||
|
startDestination = SignInScreen
|
||||||
|
) {
|
||||||
|
composable<SignInScreen> {
|
||||||
|
SignInScreenContent()
|
||||||
|
}
|
||||||
|
composable<SearchScreen> {
|
||||||
|
SearchScreenContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
object SearchScreen
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
object SignInScreen
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
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 cafe.adriel.voyager.transitions.SlideTransition
|
|
||||||
import ru.megboyzz.lks.profile.ui.screens.SearchScreen
|
|
||||||
import ru.megboyzz.lks.profile.ui.theme.MainTheme
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MainNavigator(screen: Screen) {
|
|
||||||
BottomSheetNavigator(
|
|
||||||
sheetShape = RoundedCornerShape(12.dp)
|
|
||||||
) {
|
|
||||||
MainTheme {
|
|
||||||
Navigator(screen) {
|
|
||||||
SlideTransition(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,9 +45,9 @@ import androidx.compose.ui.layout.onSizeChanged
|
|||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
|
|
||||||
import ru.megboyzz.lks.profile.R
|
import ru.megboyzz.lks.profile.R
|
||||||
import ru.megboyzz.lks.profile.domain.entities.LksRequest
|
import ru.megboyzz.lks.profile.domain.entities.LksRequest
|
||||||
|
import ru.megboyzz.lks.profile.domain.entities.LksResponse
|
||||||
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
||||||
import ru.megboyzz.lks.profile.domain.entities.Student
|
import ru.megboyzz.lks.profile.domain.entities.Student
|
||||||
import ru.megboyzz.lks.profile.ui.asPainter
|
import ru.megboyzz.lks.profile.ui.asPainter
|
||||||
@@ -171,7 +171,7 @@ fun SearchContextMenu(
|
|||||||
onSearch: (LksRequest) -> Unit
|
onSearch: (LksRequest) -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val bottomSheetNavigator = LocalBottomSheetNavigator.current
|
|
||||||
|
|
||||||
var name by remember { mutableStateOf("") }
|
var name by remember { mutableStateOf("") }
|
||||||
var surname by remember { mutableStateOf("") }
|
var surname by remember { mutableStateOf("") }
|
||||||
@@ -231,7 +231,7 @@ fun SearchContextMenu(
|
|||||||
department = departamnet.ifEmpty { null }
|
department = departamnet.ifEmpty { null }
|
||||||
)
|
)
|
||||||
onSearch(lksRequest)
|
onSearch(lksRequest)
|
||||||
bottomSheetNavigator?.hide()
|
//bottomSheetNavigator?.hide()
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Text("Поиск")
|
Text("Поиск")
|
||||||
|
|||||||
@@ -15,12 +15,14 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
import androidx.compose.material.icons.filled.Search
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
@@ -113,6 +115,8 @@ fun MainScaffold(
|
|||||||
content: @Composable (PaddingValues) -> Unit
|
content: @Composable (PaddingValues) -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
Surface(
|
Surface(
|
||||||
@@ -120,7 +124,23 @@ fun MainScaffold(
|
|||||||
modifier = Modifier.clickableWithNoEffect(onTopClick)
|
modifier = Modifier.clickableWithNoEffect(onTopClick)
|
||||||
) {
|
) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text("LKS Search") }
|
title = { Text("LKS Search") },
|
||||||
|
actions = {
|
||||||
|
IconButton(onClick = { expanded =! expanded }) {
|
||||||
|
Icon(Icons.Default.MoreVert, contentDescription = "More options")
|
||||||
|
}
|
||||||
|
SimpleDropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismiss = { expanded =! expanded },
|
||||||
|
) {
|
||||||
|
SimpleDropdownMenuItem("История поиска") {
|
||||||
|
expanded =! expanded
|
||||||
|
}
|
||||||
|
SimpleDropdownMenuItem("Избранное") {
|
||||||
|
expanded =! expanded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
+12
-16
@@ -1,25 +1,21 @@
|
|||||||
package ru.megboyzz.lks.profile.ui.model
|
package ru.megboyzz.lks.profile.ui.model
|
||||||
|
|
||||||
import android.util.Log
|
import androidx.lifecycle.ViewModel
|
||||||
import cafe.adriel.voyager.core.model.ScreenModel
|
import androidx.lifecycle.viewModelScope
|
||||||
import cafe.adriel.voyager.core.model.screenModelScope
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.megboyzz.lks.profile.domain.entities.LksRequest
|
import ru.megboyzz.lks.profile.domain.entities.LksRequest
|
||||||
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
import ru.megboyzz.lks.profile.domain.entities.LksResponse
|
||||||
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
|
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
|
||||||
import java.io.Serializable
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SearchScreenModel @Inject constructor(
|
@HiltViewModel
|
||||||
|
class SearchViewModel @Inject constructor(
|
||||||
private val lksRepository: LksRepository,
|
private val lksRepository: LksRepository,
|
||||||
) : ScreenModel, Serializable {
|
) : ViewModel() {
|
||||||
|
|
||||||
init {
|
|
||||||
Log.i(this::class.simpleName, "its new init!")
|
|
||||||
}
|
|
||||||
|
|
||||||
private val _request = MutableStateFlow(LksRequest())
|
private val _request = MutableStateFlow(LksRequest())
|
||||||
val request = _request.asStateFlow()
|
val request = _request.asStateFlow()
|
||||||
@@ -27,7 +23,7 @@ class SearchScreenModel @Inject constructor(
|
|||||||
private val _curPageNumber = MutableStateFlow(1)
|
private val _curPageNumber = MutableStateFlow(1)
|
||||||
val curPageNumber = _curPageNumber.asStateFlow()
|
val curPageNumber = _curPageNumber.asStateFlow()
|
||||||
|
|
||||||
private val _responseList = MutableStateFlow(LksStudent())
|
private val _responseList = MutableStateFlow(LksResponse())
|
||||||
val responseList = _responseList.asStateFlow()
|
val responseList = _responseList.asStateFlow()
|
||||||
|
|
||||||
sealed class UiState(val status: String? = null) {
|
sealed class UiState(val status: String? = null) {
|
||||||
@@ -48,11 +44,11 @@ class SearchScreenModel @Inject constructor(
|
|||||||
|
|
||||||
suspend fun resetStudents() {
|
suspend fun resetStudents() {
|
||||||
_curPageNumber.value = 1
|
_curPageNumber.value = 1
|
||||||
_responseList.emit(LksStudent())
|
_responseList.emit(LksResponse())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun newSearch(request: LksRequest) {
|
fun newSearch(request: LksRequest) {
|
||||||
screenModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
state.emit(UiState.Loading)
|
state.emit(UiState.Loading)
|
||||||
resetStudents()
|
resetStudents()
|
||||||
state.emit(update(request))
|
state.emit(update(request))
|
||||||
@@ -70,9 +66,9 @@ class SearchScreenModel @Inject constructor(
|
|||||||
if(result.isFailure)
|
if(result.isFailure)
|
||||||
return UiState.Error("Ошибка :-(")
|
return UiState.Error("Ошибка :-(")
|
||||||
|
|
||||||
val list = result.getOrElse { LksStudent() }
|
val list = result.getOrElse { LksResponse() }
|
||||||
|
|
||||||
val updatedStudents = LksStudent(
|
val updatedStudents = LksResponse(
|
||||||
students = _responseList.value.students + list.students,
|
students = _responseList.value.students + list.students,
|
||||||
availablePages = list.availablePages
|
availablePages = list.availablePages
|
||||||
)
|
)
|
||||||
+25
-31
@@ -2,17 +2,11 @@ package ru.megboyzz.lks.profile.ui.model
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import cafe.adriel.voyager.core.model.ScreenModel
|
import androidx.lifecycle.ViewModel
|
||||||
import cafe.adriel.voyager.core.model.screenModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import cafe.adriel.voyager.hilt.ScreenModelFactory
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import cafe.adriel.voyager.navigator.Navigator
|
|
||||||
import dagger.assisted.Assisted
|
|
||||||
import dagger.assisted.AssistedFactory
|
|
||||||
import dagger.assisted.AssistedInject
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -20,16 +14,15 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.megboyzz.lks.profile.domain.DefaultCookies
|
import ru.megboyzz.lks.profile.domain.DefaultCookies
|
||||||
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
|
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
|
||||||
import ru.megboyzz.lks.profile.ui.screens.SearchScreen
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
class SignInScreenModel @AssistedInject constructor(
|
class SignInViewModel @Inject constructor(
|
||||||
@ApplicationContext val context: Context,
|
@ApplicationContext val context: Context,
|
||||||
private val lksRepository: LksRepository,
|
private val lksRepository: LksRepository,
|
||||||
@Assisted private val navigator: Navigator,
|
|
||||||
@DefaultCookies
|
@DefaultCookies
|
||||||
private val defaultCookies: Map<String, String>
|
private val defaultCookies: Map<String, String>
|
||||||
) : ScreenModel {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _username = MutableStateFlow("")
|
private val _username = MutableStateFlow("")
|
||||||
val username = _username.asStateFlow()
|
val username = _username.asStateFlow()
|
||||||
@@ -51,28 +44,35 @@ class SignInScreenModel @AssistedInject constructor(
|
|||||||
|
|
||||||
private var cookie: Map<String, String> = mapOf()
|
private var cookie: Map<String, String> = mapOf()
|
||||||
|
|
||||||
private fun makeSuspendToast(text: String) = screenModelScope.launch(Dispatchers.Main) {
|
private fun makeSuspendToast(text: String) = viewModelScope.launch(Dispatchers.Main) {
|
||||||
Toast.makeText(context, text, Toast.LENGTH_LONG).show()
|
Toast.makeText(context, text, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
private var isUseDefaultCookie = false
|
||||||
|
|
||||||
screenModelScope.launch(Dispatchers.IO) {
|
init {
|
||||||
_loadingScreen.emit(true)
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
state.emit(SignInState.Loading)
|
||||||
cookie = lksRepository.restoreCooke()
|
cookie = lksRepository.restoreCooke()
|
||||||
//if(cookie.isEmpty()) cookie = defaultCookies
|
if(cookie.isEmpty()) {
|
||||||
|
isUseDefaultCookie = true
|
||||||
|
cookie = defaultCookies
|
||||||
|
}
|
||||||
if(lksRepository.cookiesIsValid(cookie)) {
|
if(lksRepository.cookiesIsValid(cookie)) {
|
||||||
navigator.push(SearchScreen())
|
state.emit(SignInState.Success)
|
||||||
makeSuspendToast("Успех!")
|
if(isUseDefaultCookie)
|
||||||
|
makeSuspendToast("Успех с дефолтными куками!")
|
||||||
|
else
|
||||||
|
makeSuspendToast("Успех!")
|
||||||
}else {
|
}else {
|
||||||
|
state.emit(SignInState.Error("Error!"))
|
||||||
makeSuspendToast("Не успех!")
|
makeSuspendToast("Не успех!")
|
||||||
}
|
}
|
||||||
_loadingScreen.emit(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.onEach {
|
state.onEach {
|
||||||
if(it == SignInState.Success) navigator.push(SearchScreen())
|
//if(it == SignInState.Success) navigator.push(SearchScreen())
|
||||||
}.launchIn(screenModelScope)
|
}.launchIn(viewModelScope)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ class SignInScreenModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun signIn() {
|
fun signIn() {
|
||||||
screenModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
state.emit(SignInState.Loading)
|
state.emit(SignInState.Loading)
|
||||||
cookie = lksRepository.signInAndGetCookies(_username.value, _password.value)
|
cookie = lksRepository.signInAndGetCookies(_username.value, _password.value)
|
||||||
if(cookie.isEmpty())
|
if(cookie.isEmpty())
|
||||||
@@ -96,10 +96,4 @@ class SignInScreenModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AssistedFactory
|
|
||||||
interface Factory : ScreenModelFactory {
|
|
||||||
fun create(navigator: Navigator): SignInScreenModel
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package ru.megboyzz.lks.profile.ui.provider
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import ru.megboyzz.lks.profile.MainActivity
|
||||||
|
|
||||||
|
val LocalMainActivity = compositionLocalOf<MainActivity> {
|
||||||
|
error("No MainActivity provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ActivityProvider(
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
val mainActivity = LocalContext.current as MainActivity
|
||||||
|
CompositionLocalProvider(LocalMainActivity provides mainActivity) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,72 +1,63 @@
|
|||||||
package ru.megboyzz.lks.profile.ui.screens
|
package ru.megboyzz.lks.profile.ui.screens
|
||||||
|
|
||||||
import android.widget.Toast
|
import androidx.activity.viewModels
|
||||||
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.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
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.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.pointer.PointerIcon.Companion.Text
|
import ru.megboyzz.lks.profile.domain.entities.LksStudent
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import cafe.adriel.voyager.core.screen.Screen
|
|
||||||
import cafe.adriel.voyager.hilt.getScreenModel
|
|
||||||
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
|
|
||||||
import ru.megboyzz.lks.profile.ui.components.CardsColumn
|
import ru.megboyzz.lks.profile.ui.components.CardsColumn
|
||||||
import ru.megboyzz.lks.profile.ui.components.ErrorShield
|
import ru.megboyzz.lks.profile.ui.components.ErrorShield
|
||||||
import ru.megboyzz.lks.profile.ui.components.LoadingShield
|
import ru.megboyzz.lks.profile.ui.components.LoadingShield
|
||||||
import ru.megboyzz.lks.profile.ui.components.MainScaffold
|
import ru.megboyzz.lks.profile.ui.components.MainScaffold
|
||||||
import ru.megboyzz.lks.profile.ui.components.ProfileCard
|
import ru.megboyzz.lks.profile.ui.model.SearchViewModel
|
||||||
import ru.megboyzz.lks.profile.ui.model.SearchScreenModel
|
import ru.megboyzz.lks.profile.ui.provider.LocalMainActivity
|
||||||
import ru.megboyzz.lks.profile.ui.screens.sub.LongPressMenu
|
import ru.megboyzz.lks.profile.ui.screens.sub.LongPressMenu
|
||||||
import ru.megboyzz.lks.profile.ui.screens.sub.SearchBottomScreen
|
import ru.megboyzz.lks.profile.ui.screens.sub.SearchBottomSheet
|
||||||
|
|
||||||
class SearchScreen : Screen {
|
@Composable
|
||||||
@Composable
|
fun SearchScreenContent() {
|
||||||
override fun Content() {
|
|
||||||
|
|
||||||
val bottomSheetNavigator = LocalBottomSheetNavigator.current
|
val screenModel by LocalMainActivity.current.viewModels<SearchViewModel>()
|
||||||
|
|
||||||
val screenModel = getScreenModel<SearchScreenModel>("my_tag")
|
val state by screenModel.state.collectAsState()
|
||||||
|
|
||||||
val state by screenModel.state.collectAsState()
|
val list by screenModel.responseList.collectAsState()
|
||||||
|
|
||||||
val list by screenModel.responseList.collectAsState()
|
var searchMenuExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
MainScaffold(
|
|
||||||
onFloatingButtonClick = { bottomSheetNavigator.show(SearchBottomScreen(screenModel)) },
|
|
||||||
onTopClick = { }
|
|
||||||
) {
|
|
||||||
|
|
||||||
when (state) {
|
|
||||||
is SearchScreenModel.UiState.Loading -> LoadingShield("Загрузка челиков")
|
|
||||||
is SearchScreenModel.UiState.Error -> ErrorShield(state.status)
|
|
||||||
else -> {
|
|
||||||
CardsColumn(
|
|
||||||
modifier = Modifier.padding(it),
|
|
||||||
lksStudents = list.students,
|
|
||||||
onLongPress = { student -> bottomSheetNavigator.show(LongPressMenu(student)) },
|
|
||||||
onColumnOverflow = {
|
|
||||||
//Toast.makeText(context, "Hello!", Toast.LENGTH_SHORT).show()
|
|
||||||
screenModel.nextPage()
|
|
||||||
//screenModel.update(screenModel.request.value)
|
|
||||||
//screenModel.nextPage()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var isLongPressedStudent by remember {
|
||||||
|
mutableStateOf<LksStudent?>(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MainScaffold(
|
||||||
|
onFloatingButtonClick = { searchMenuExpanded =! searchMenuExpanded },
|
||||||
|
onTopClick = { }
|
||||||
|
) {
|
||||||
|
when (state) {
|
||||||
|
is SearchViewModel.UiState.Loading -> LoadingShield("Загрузка челиков")
|
||||||
|
is SearchViewModel.UiState.Error -> ErrorShield(state.status)
|
||||||
|
else -> {
|
||||||
|
CardsColumn(
|
||||||
|
modifier = Modifier.padding(it),
|
||||||
|
lksStudents = list.students,
|
||||||
|
onLongPress = { student -> isLongPressedStudent = student },
|
||||||
|
onColumnOverflow = {
|
||||||
|
screenModel.nextPage()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(searchMenuExpanded)
|
||||||
|
SearchBottomSheet { searchMenuExpanded =! searchMenuExpanded }
|
||||||
|
|
||||||
|
if(isLongPressedStudent != null)
|
||||||
|
LongPressMenu(isLongPressedStudent!!) { isLongPressedStudent = null }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
package ru.megboyzz.lks.profile.ui.screens
|
|
||||||
|
|
||||||
import android.os.Parcel
|
|
||||||
import android.os.Parcelable
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.OutlinedButton
|
|
||||||
import androidx.compose.material3.OutlinedTextField
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
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 ru.megboyzz.lks.profile.ui.components.LoadingShield
|
|
||||||
import ru.megboyzz.lks.profile.ui.model.SignInScreenModel
|
|
||||||
import ru.megboyzz.lks.profile.ui.theme.MainTheme
|
|
||||||
|
|
||||||
class SignInScreen : Screen {
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun Content() = MainTheme {
|
|
||||||
|
|
||||||
val navigator = LocalNavigator.current!!
|
|
||||||
|
|
||||||
val viewModel = getScreenModel<SignInScreenModel, SignInScreenModel.Factory> { assistedFactory ->
|
|
||||||
assistedFactory.create(navigator)
|
|
||||||
}
|
|
||||||
|
|
||||||
val username by viewModel.username.collectAsState()
|
|
||||||
val password by viewModel.password.collectAsState()
|
|
||||||
|
|
||||||
val state by viewModel.state.collectAsState()
|
|
||||||
|
|
||||||
val loading by viewModel.loadingScreen.collectAsState()
|
|
||||||
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
|
|
||||||
if(loading){
|
|
||||||
LoadingShield("Проверка твоих куки файлов :-)")
|
|
||||||
} else {
|
|
||||||
|
|
||||||
OutlinedTextField(
|
|
||||||
value = username,
|
|
||||||
onValueChange = { viewModel.setUsername(it) }
|
|
||||||
)
|
|
||||||
|
|
||||||
OutlinedTextField(
|
|
||||||
value = password,
|
|
||||||
onValueChange = { viewModel.setPassword(it) }
|
|
||||||
)
|
|
||||||
|
|
||||||
OutlinedButton(
|
|
||||||
onClick = viewModel::signIn
|
|
||||||
) {
|
|
||||||
Text("Войти")
|
|
||||||
}
|
|
||||||
|
|
||||||
when (state) {
|
|
||||||
is SignInScreenModel.SignInState.Idle -> Text("")
|
|
||||||
is SignInScreenModel.SignInState.Success -> Text(state.status ?: "")
|
|
||||||
is SignInScreenModel.SignInState.Loading -> CircularProgressIndicator()
|
|
||||||
is SignInScreenModel.SignInState.Error -> Text(state.status ?: "Ошибка")
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
package ru.megboyzz.lks.profile.ui.screens
|
||||||
|
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.OutlinedButton
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ru.megboyzz.lks.profile.ui.components.LoadingShield
|
||||||
|
import ru.megboyzz.lks.profile.ui.model.SignInViewModel
|
||||||
|
import ru.megboyzz.lks.profile.ui.provider.LocalMainActivity
|
||||||
|
import ru.megboyzz.lks.profile.ui.theme.MainTheme
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SignInScreenContent() = MainTheme {
|
||||||
|
|
||||||
|
val viewModel by LocalMainActivity.current.viewModels<SignInViewModel>()
|
||||||
|
|
||||||
|
val username by viewModel.username.collectAsState()
|
||||||
|
val password by viewModel.password.collectAsState()
|
||||||
|
|
||||||
|
val state by viewModel.state.collectAsState()
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
|
||||||
|
when(state) {
|
||||||
|
is SignInViewModel.SignInState.Loading, SignInViewModel.SignInState.Success -> LoadingShield("Проверка твоих куки файлов :-)")
|
||||||
|
else -> {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = username,
|
||||||
|
onValueChange = { viewModel.setUsername(it) }
|
||||||
|
)
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = password,
|
||||||
|
onValueChange = { viewModel.setPassword(it) }
|
||||||
|
)
|
||||||
|
|
||||||
|
OutlinedButton(
|
||||||
|
onClick = viewModel::signIn
|
||||||
|
) {
|
||||||
|
Text("Войти")
|
||||||
|
}
|
||||||
|
|
||||||
|
when (state) {
|
||||||
|
is SignInViewModel.SignInState.Idle -> Text("")
|
||||||
|
is SignInViewModel.SignInState.Success -> Text(state.status ?: "")
|
||||||
|
is SignInViewModel.SignInState.Loading -> CircularProgressIndicator()
|
||||||
|
is SignInViewModel.SignInState.Error -> Text(state.status ?: "Ошибка")
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,38 +3,48 @@ package ru.megboyzz.lks.profile.ui.screens.sub
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.platform.LocalContext
|
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.domain.entities.LksStudent
|
||||||
import ru.megboyzz.lks.profile.ui.components.LongPressCardContextMenu
|
import ru.megboyzz.lks.profile.ui.components.LongPressCardContextMenu
|
||||||
import ru.megboyzz.lks.profile.ui.copyToClipboard
|
import ru.megboyzz.lks.profile.ui.copyToClipboard
|
||||||
import java.io.Serializable
|
import ru.megboyzz.lks.profile.ui.goToVK
|
||||||
|
|
||||||
|
|
||||||
class LongPressMenu(private val lksStudent: LksStudent) : Screen, Serializable {
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun LongPressMenu(
|
||||||
|
lksStudent: LksStudent,
|
||||||
|
onDismiss: () -> Unit
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
@Composable
|
val sheetState = rememberModalBottomSheetState()
|
||||||
override fun Content() {
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
val context = LocalContext.current
|
|
||||||
|
|
||||||
|
ModalBottomSheet(
|
||||||
|
sheetState = sheetState,
|
||||||
|
onDismissRequest = onDismiss
|
||||||
|
) {
|
||||||
LongPressCardContextMenu(
|
LongPressCardContextMenu(
|
||||||
lksStudent = lksStudent,
|
lksStudent = lksStudent,
|
||||||
onCopyName = {
|
onCopyName = context::copyToClipboard,
|
||||||
context.copyToClipboard(lksStudent.studentFullName.toString())
|
onCopyGroup = context::copyToClipboard,
|
||||||
},
|
onGoToVk = {
|
||||||
onCopyGroup = {
|
|
||||||
context.copyToClipboard(lksStudent.group.toString())
|
|
||||||
},
|
|
||||||
onGoToVk = {
|
|
||||||
Toast.makeText(context, "Переход на VK", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Переход на VK", Toast.LENGTH_SHORT).show()
|
||||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://vk.com/search?q=${lksStudent.studentFullName?.split(" ")?.dropLast(1)?.joinToString(" ")}"))
|
|
||||||
browserIntent.`package` = "com.vkontakte.android"
|
val searchString = lksStudent
|
||||||
context.startActivity(browserIntent)
|
.studentFullName
|
||||||
|
?.split(" ")
|
||||||
|
?.dropLast(1)
|
||||||
|
?.joinToString(" ") ?: ""
|
||||||
|
|
||||||
|
context.goToVK(searchString)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package ru.megboyzz.lks.profile.ui.screens.sub
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
|
||||||
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
|
|
||||||
import ru.megboyzz.lks.profile.ui.theme.MainTheme
|
|
||||||
import java.io.Serializable
|
|
||||||
|
|
||||||
class SearchBottomScreen(
|
|
||||||
private val searchScreenModel: SearchScreenModel
|
|
||||||
) : Screen, Serializable {
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun Content() = MainTheme {
|
|
||||||
|
|
||||||
//val screenModel = getScreenModel<SearchScreenModel>("my_tag")
|
|
||||||
val screenModel = rememberScreenModel { searchScreenModel }
|
|
||||||
|
|
||||||
SearchContextMenu { lksRequest -> screenModel.newSearch(lksRequest) }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
package ru.megboyzz.lks.profile.ui.screens.sub
|
||||||
|
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import ru.megboyzz.lks.profile.ui.components.SearchContextMenu
|
||||||
|
import ru.megboyzz.lks.profile.ui.model.SearchViewModel
|
||||||
|
import ru.megboyzz.lks.profile.ui.provider.LocalMainActivity
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun SearchBottomSheet(onDismiss: () -> Unit) {
|
||||||
|
|
||||||
|
val viewModel by LocalMainActivity.current.viewModels<SearchViewModel>()
|
||||||
|
|
||||||
|
val sheetState = rememberModalBottomSheetState()
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
ModalBottomSheet(
|
||||||
|
sheetState = sheetState,
|
||||||
|
onDismissRequest = onDismiss
|
||||||
|
) {
|
||||||
|
SearchContextMenu { lksRequest ->
|
||||||
|
viewModel.newSearch(lksRequest)
|
||||||
|
coroutineScope.launch { sheetState.hide() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -11,11 +11,14 @@ lifecycleRuntimeKtx = "2.8.4"
|
|||||||
activityCompose = "1.9.1"
|
activityCompose = "1.9.1"
|
||||||
composeBom = "2024.04.01"
|
composeBom = "2024.04.01"
|
||||||
jetbrainsKotlinJvm = "2.0.0"
|
jetbrainsKotlinJvm = "2.0.0"
|
||||||
appcompat = "1.7.0"
|
composeNavigation = "2.8.0-alpha08"
|
||||||
material = "1.12.0"
|
room_version = "2.6.1"
|
||||||
voyagerVersion = "1.1.0-beta02"
|
serialization = "1.6.3"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room_version" }
|
||||||
|
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room_version" }
|
||||||
|
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room_version" }
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroidCompiler" }
|
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroidCompiler" }
|
||||||
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroidCompiler" }
|
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroidCompiler" }
|
||||||
@@ -33,13 +36,8 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
|
|||||||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||||
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "composeNavigation" }
|
||||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization"}
|
||||||
voyager-bottom-sheet-navigator = { module = "cafe.adriel.voyager:voyager-bottom-sheet-navigator", version.ref = "voyagerVersion" }
|
|
||||||
voyager-hilt = { module = "cafe.adriel.voyager:voyager-hilt", version.ref = "voyagerVersion" }
|
|
||||||
voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyagerVersion" }
|
|
||||||
voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyagerVersion" }
|
|
||||||
voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyagerVersion" }
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
@@ -47,4 +45,5 @@ kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
|||||||
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "jetbrainsKotlinJvm" }
|
jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "jetbrainsKotlinJvm" }
|
||||||
android-library = { id = "com.android.library", version.ref = "agp" }
|
android-library = { id = "com.android.library", version.ref = "agp" }
|
||||||
|
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user