main funtionality

This commit is contained in:
2024-09-23 01:05:47 +03:00
parent 7d3d3517c5
commit e32b4feeef
10 changed files with 93 additions and 46 deletions
@@ -31,7 +31,7 @@ class MainActivity : ComponentActivity() {
enableEdgeToEdge() enableEdgeToEdge()
setContent { setContent {
MainNavigator(SearchScreen()) MainNavigator(SignInScreen())
} }
} }
} }
@@ -1,5 +1,6 @@
package ru.megboyzz.lks.profile.data package ru.megboyzz.lks.profile.data
import android.util.Log
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.LksResponse
@@ -17,6 +18,7 @@ private fun Connection.dataMap(vararg pairs: Pair<String, String>) = this.data(m
suspend fun signInLks(username: String, password: String) = withContext(Dispatchers.IO) { suspend fun signInLks(username: String, password: String) = withContext(Dispatchers.IO) {
val cookies = Jsoup val cookies = Jsoup
.connect("https://lk.mirea.ru/auth.php?login=yes") .connect("https://lk.mirea.ru/auth.php?login=yes")
//.userAgent("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36")
.dataMap( .dataMap(
"AUTH_FORM" to "Y", "AUTH_FORM" to "Y",
"TYPE" to "AUTH", "TYPE" to "AUTH",
@@ -35,33 +37,47 @@ suspend fun signInLks(username: String, password: String) = withContext(Dispatch
return@withContext mapOf<String, String>() return@withContext mapOf<String, String>()
} }
suspend fun fakeConnect(cookies: Cookies) = withContext(Dispatchers.IO) { fun fakeConnect(cookies: Cookies) {
Jsoup Jsoup
.connect("https://lk.mirea.ru/") .connect("https://lk.mirea.ru/")
//.userAgent("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36")
.cookies(cookies) .cookies(cookies)
.referrer("https://lk.mirea.ru/") .referrer("https://lk.mirea.ru/")
.execute() .execute()
} }
suspend fun getPage(payload: LksRequest, cookies: Cookies, page: Int) = withContext(Dispatchers.IO) { fun getProfilePage(payload: LksRequest, cookies: Cookies, page: Int): Document {
val sesid = cookies["BITRIX_SM_UIDH"] val sesid = cookies["BITRIX_SM_UIDH"]
//Log.i("TEXT", "Its begin! 1")
fakeConnect(cookies) fakeConnect(cookies)
Jsoup //Log.i("TEXT", "Its end! 1")
//Log.i("TEXT", "Its begin! 2")
val conn = Jsoup
.connect("https://lk.mirea.ru/staff/students/?${payload.getSubmitUrlPath(sesid ?: "")}&PAGEN_1=$page") .connect("https://lk.mirea.ru/staff/students/?${payload.getSubmitUrlPath(sesid ?: "")}&PAGEN_1=$page")
//.userAgent("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36")
.cookies(cookies) .cookies(cookies)
.referrer("https://lk.mirea.ru/") .referrer("https://lk.mirea.ru/")
.execute().parse() .execute()
//Log.i("TEXT", "Its end! 2")
val doc = conn.parse()
//Log.i("TEXT", "Its end! 3")
println(doc.body())
return doc
} }
fun Document.getTotalPages() = kotlin.runCatching { 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 Document.findStudentsInPage(): LksResponse { fun findStudentsInPage(document: Document): LksResponse {
val table = this.select("body > div.container > table > tbody") ?: return LksResponse() val table = document.select("body > div.container > table > tbody") ?: return LksResponse()
val students = table.select("tr").map { val students = table.select("tr").map {
@@ -88,7 +104,7 @@ fun Document.findStudentsInPage(): LksResponse {
return LksResponse( return LksResponse(
students = students, students = students,
availablePages = this.getTotalPages() availablePages = document.getTotalPages()
) )
} }
@@ -1,8 +1,10 @@
package ru.megboyzz.lks.profile.data.repositories package ru.megboyzz.lks.profile.data.repositories
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log
import androidx.core.content.edit import androidx.core.content.edit
import ru.megboyzz.lks.profile.data.findStudentsInPage import ru.megboyzz.lks.profile.data.findStudentsInPage
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
@@ -23,7 +25,7 @@ class LksRepositoryImpl @Inject constructor(
): Map<String, String> = signInLks(username, password) ): Map<String, String> = signInLks(username, password)
override suspend fun cookiesIsValid(cookie: Map<String, String>): Boolean { override suspend fun cookiesIsValid(cookie: Map<String, String>): Boolean {
return true return false
} }
@@ -47,9 +49,13 @@ class LksRepositoryImpl @Inject constructor(
override suspend fun getPage(lksRequest: LksRequest, cookie: Map<String, String>, pageNumber: Int): Result<LksResponse> { override suspend fun getPage(lksRequest: LksRequest, cookie: Map<String, String>, pageNumber: Int): Result<LksResponse> {
val document = ru.megboyzz.lks.profile.data.getPage(lksRequest, cookie, pageNumber) Log.i("TEXT", "Its begin doc!")
val document = getProfilePage(lksRequest, cookie, pageNumber)
Log.i("TEXT", "Its begin end!")
val page = document.findStudentsInPage() Log.i("TEXT", "Its begin!")
val page = findStudentsInPage(document)
Log.i("TEXT", "Its end!")
return if(page == LksResponse()) return if(page == LksResponse())
Result.failure(Exception()) Result.failure(Exception())
@@ -1,6 +1,8 @@
package ru.megboyzz.lks.profile.ui package ru.megboyzz.lks.profile.ui
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material.ripple.rememberRipple import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -9,11 +11,16 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import kotlin.concurrent.thread import kotlin.concurrent.thread
@OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun Modifier.clickableWithNormalRipple(onClick: () -> Unit) = this.clickable( fun Modifier.clickableWithNormalRipple(
onClick: () -> Unit = {},
onLongClick: () -> Unit = {},
) = this.combinedClickable(
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(bounded = true), indication = rememberRipple(bounded = true),
onClick = onClick onClick = onClick,
onLongClick = onLongClick
) )
@Composable @Composable
@@ -224,12 +224,12 @@ fun SearchContextMenu(
onClick = { onClick = {
val lksRequest = LksRequest( val lksRequest = LksRequest(
student = Student( student = Student(
name = name, name = name.ifEmpty { null },
surname = family, surname = family.ifEmpty { null },
patronymic = surname patronymic = surname.ifEmpty { null },
), ),
group = group, group = group.ifEmpty { null },
department = departamnet department = departamnet.ifEmpty { null }
) )
onSearch(lksRequest) onSearch(lksRequest)
bottomSheetNavigator?.hide() bottomSheetNavigator?.hide()
@@ -60,7 +60,10 @@ fun ProfileCard(
shape = RoundedCornerShape(16.dp) shape = RoundedCornerShape(16.dp)
) )
.defaultMinSize(minWidth = 240.dp) .defaultMinSize(minWidth = 240.dp)
.clickableWithNormalRipple { toggled =! toggled }, .clickableWithNormalRipple(
onClick = { toggled =! toggled },
onLongClick = onLongPress
),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Column( Column(
@@ -5,6 +5,7 @@ import cafe.adriel.voyager.core.model.screenModelScope
import cafe.adriel.voyager.hilt.ScreenModelFactory import cafe.adriel.voyager.hilt.ScreenModelFactory
import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.Navigator
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
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.flow.launchIn import kotlinx.coroutines.flow.launchIn
@@ -46,19 +47,17 @@ class SearchScreenModel @Inject constructor(
update() update()
}*/ }*/
_request.onEach {
update()
}.launchIn(screenModelScope)
} }
fun nextPage() = screenModelScope.launch { _curPageNumber.emit(_curPageNumber.value++) } fun nextPage() = screenModelScope.launch { _curPageNumber.emit(_curPageNumber.value++) }
private fun update() = screenModelScope.launch { fun newSearch(request: LksRequest) = screenModelScope.launch(Dispatchers.IO) {
state.emit(UiState.Loading) state.emit(UiState.Loading)
val result = lksRepository.getPage(_request.value, cookies, curPageNumber.value) val repoCookies = lksRepository.restoreCooke()
val result = lksRepository.getPage(request, repoCookies, curPageNumber.value)
if(result.isFailure) { if(result.isFailure) {
state.emit(UiState.Error("Ошибка :-(")) state.emit(UiState.Error("Ошибка :-("))
@@ -72,9 +71,5 @@ class SearchScreenModel @Inject constructor(
state.emit(UiState.Idle) state.emit(UiState.Idle)
} }
fun newSearch(request: LksRequest) = screenModelScope.launch {
_request.emit(request)
}
} }
@@ -1,6 +1,9 @@
package ru.megboyzz.lks.profile.ui.screens package ru.megboyzz.lks.profile.ui.screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
@@ -8,6 +11,7 @@ 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.Modifier
import androidx.compose.ui.input.pointer.PointerIcon.Companion.Text import androidx.compose.ui.input.pointer.PointerIcon.Companion.Text
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
@@ -25,31 +29,38 @@ class SearchScreen : Screen {
val bottomSheetNavigator = LocalBottomSheetNavigator.current val bottomSheetNavigator = LocalBottomSheetNavigator.current
val screenModel = getScreenModel<SearchScreenModel>() 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()
MainScaffold( MainScaffold(
onFloatingButtonClick = { bottomSheetNavigator.show(SearchBottomScreen()) } onFloatingButtonClick = { bottomSheetNavigator.show(SearchBottomScreen(screenModel)) }
) { ) {
LazyColumn( Column (
contentPadding = PaddingValues(8.dp) modifier = Modifier.padding(it)
) { ) {
item { LazyColumn(
when(state) { contentPadding = PaddingValues(8.dp),
is SearchScreenModel.UiState.Loading -> CircularProgressIndicator() verticalArrangement = Arrangement.spacedBy(4.dp)
is SearchScreenModel.UiState.Error -> Text(state.status ?: "Ошибка") ) {
SearchScreenModel.UiState.Idle -> {}
item {
when(state) {
is SearchScreenModel.UiState.Loading -> CircularProgressIndicator()
is SearchScreenModel.UiState.Error -> Text(state.status ?: "Ошибка")
SearchScreenModel.UiState.Idle -> { Text("Idle") }
}
}
items(list.students) {
ProfileCard(
lksStudent = it,
onLongPress = { bottomSheetNavigator.show(LongPressMenu(it)) }
)
} }
}
items(list.students) {
ProfileCard(
lksStudent = it,
onLongPress = { bottomSheetNavigator.show(LongPressMenu(it)) }
)
} }
} }
@@ -1,5 +1,7 @@
package ru.megboyzz.lks.profile.ui.screens.sub package ru.megboyzz.lks.profile.ui.screens.sub
import android.content.Intent
import android.net.Uri
import android.widget.Toast import android.widget.Toast
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@@ -7,6 +9,7 @@ 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
class LongPressMenu(private val lksStudent: LksStudent) : Screen { class LongPressMenu(private val lksStudent: LksStudent) : Screen {
@Composable @Composable
@@ -18,6 +21,9 @@ class LongPressMenu(private val lksStudent: LksStudent) : Screen {
lksStudent = lksStudent lksStudent = lksStudent
) { ) {
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}"))
browserIntent.`package` = "com.vkontakte.android"
context.startActivity(browserIntent);
} }
@@ -1,17 +1,20 @@
package ru.megboyzz.lks.profile.ui.screens.sub package ru.megboyzz.lks.profile.ui.screens.sub
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.hilt.getScreenModel import cafe.adriel.voyager.hilt.getScreenModel
import ru.megboyzz.lks.profile.ui.components.SearchContextMenu import ru.megboyzz.lks.profile.ui.components.SearchContextMenu
import ru.megboyzz.lks.profile.ui.model.SearchScreenModel import ru.megboyzz.lks.profile.ui.model.SearchScreenModel
class SearchBottomScreen : Screen { class SearchBottomScreen(
private val searchScreenModel: SearchScreenModel
) : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val screenModel = getScreenModel<SearchScreenModel>() val screenModel = rememberScreenModel { searchScreenModel }
SearchContextMenu { lksRequest -> screenModel.newSearch(lksRequest) } SearchContextMenu { lksRequest -> screenModel.newSearch(lksRequest) }