main funtionality
This commit is contained in:
@@ -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,26 +29,32 @@ 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)
|
||||||
) {
|
) {
|
||||||
|
LazyColumn(
|
||||||
|
contentPadding = PaddingValues(8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
|
|
||||||
item {
|
item {
|
||||||
when(state) {
|
when(state) {
|
||||||
is SearchScreenModel.UiState.Loading -> CircularProgressIndicator()
|
is SearchScreenModel.UiState.Loading -> CircularProgressIndicator()
|
||||||
is SearchScreenModel.UiState.Error -> Text(state.status ?: "Ошибка")
|
is SearchScreenModel.UiState.Error -> Text(state.status ?: "Ошибка")
|
||||||
SearchScreenModel.UiState.Idle -> {}
|
SearchScreenModel.UiState.Idle -> { Text("Idle") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
items(list.students) {
|
items(list.students) {
|
||||||
ProfileCard(
|
ProfileCard(
|
||||||
lksStudent = it,
|
lksStudent = it,
|
||||||
@@ -52,6 +62,7 @@ class SearchScreen : Screen {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user