sign in released

This commit is contained in:
2024-09-21 19:38:16 +03:00
parent 16f284b30a
commit 689c23921d
29 changed files with 216 additions and 157 deletions
Generated
+1
View File
@@ -0,0 +1 @@
LKS PROFILE
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+2 -2
View File
@@ -59,8 +59,8 @@ dependencies {
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
implementation("com.google.dagger:hilt-android:2.51.1")
kapt("com.google.dagger:hilt-android-compiler:2.51.1")
implementation(libs.hilt.android)
kapt(libs.hilt.android.compiler)
implementation(libs.voyager.navigator)
+1
View File
@@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".data.App"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
@@ -12,9 +12,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import cafe.adriel.voyager.navigator.Navigator
import dagger.hilt.android.AndroidEntryPoint
import ru.megboyzz.lks.profile.ui.screens.SignInScreen
import ru.megboyzz.lks.profile.ui.theme.MainTheme
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -0,0 +1,8 @@
package ru.megboyzz.lks.profile.data
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
import dagger.hilt.android.qualifiers.ApplicationContext
@HiltAndroidApp
class App : Application()
@@ -0,0 +1,38 @@
package ru.megboyzz.lks.profile.data.di
import android.content.Context
import android.content.SharedPreferences
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import ru.megboyzz.lks.profile.data.repositories.LksRepositoryImpl
import ru.megboyzz.lks.profile.domain.CookiesPrefs
import ru.megboyzz.lks.profile.domain.DefaultCookies
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
@Module
@InstallIn(SingletonComponent::class)
class DataModule {
@Provides
fun providesLksRepo(
@CookiesPrefs
cookiesPrefs: SharedPreferences
): LksRepository = LksRepositoryImpl(cookiesPrefs)
@Provides
fun providesCookiesPrefs(@ApplicationContext context: Context): SharedPreferences =
context.getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
@Provides
@DefaultCookies
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"
)
}
@@ -22,6 +22,10 @@ class LksRepositoryImpl @Inject constructor(
password: String
): Map<String, String> = signInLks(username, password)
override suspend fun cookiesIsValid(cookie: Map<String, String>): Boolean {
return true
}
override fun saveCookie(cookie: Map<String, String>) {
sharedPreferences.edit {
@@ -1,5 +1,6 @@
package ru.megboyzz.lks.profile.domain
import javax.inject.Qualifier
import javax.inject.Scope
@Scope
@@ -9,4 +10,7 @@ annotation class NetworkDispatcherScope
annotation class LocalDispatcherScope
@Scope
annotation class CookiesPrefs
annotation class CookiesPrefs
@Qualifier
annotation class DefaultCookies
@@ -4,9 +4,9 @@ package ru.megboyzz.lks.profile.domain.entities
* Класс описывающий запрос/ответ к/от лкс
*/
data class LksRequest(
var student: Student,
var group: String?,
var department: String?
var student: Student? = null,
var group: String? = null,
var department: String? = null
){
/**
* Метод для получения пути после https://lk.mirea.ru/staff/students? ...
@@ -7,6 +7,8 @@ interface LksRepository {
suspend fun signInAndGetCookies(username: String, password: String): Map<String, String>
suspend fun cookiesIsValid(cookie: Map<String, String>): Boolean
suspend fun getPage(lksRequest: LksRequest, cookie: Map<String, String>, pageNumber: Int): Result<LksResponse>
fun saveCookie(cookie: Map<String, String>)
@@ -1,28 +0,0 @@
package ru.megboyzz.lks.profile.domain.usecases
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import ru.megboyzz.lks.profile.data.signInLks
import ru.megboyzz.lks.profile.domain.NetworkDispatcherScope
import ru.megboyzz.lks.profile.domain.entities.Resource
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
import javax.inject.Inject
class SignInUseCase @Inject constructor(
private val lksRepository: LksRepository,
@NetworkDispatcherScope
private val coroutineDispatcher: CoroutineDispatcher
) {
suspend operator fun invoke(username: String, password: String): Resource = withContext(coroutineDispatcher) {
val cookies = signInLks(username, password)
return@withContext if(cookies.containsKey("BITRIX_SM_UIDH")) {
lksRepository.saveCookie(cookies)
Resource.Success("SignIn success")
}else
Resource.Error(message = "Wrong creds")
}
}
@@ -1,20 +0,0 @@
package ru.megboyzz.lks.profile.domain.usecases.fav
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import ru.megboyzz.lks.profile.domain.LocalDispatcherScope
import ru.megboyzz.lks.profile.domain.entities.LksResponse
import ru.megboyzz.lks.profile.domain.repositories.StudentRepository
import javax.inject.Inject
class AddFavoriteUseCase @Inject constructor(
private val studentRepository: StudentRepository,
@LocalDispatcherScope
private val coroutineDispatcher: CoroutineDispatcher
) {
suspend operator fun invoke(lksResponse: LksResponse) = withContext(coroutineDispatcher) {
studentRepository.addStudent(lksResponse)
}
}
@@ -1,17 +0,0 @@
package ru.megboyzz.lks.profile.domain.usecases.fav
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import ru.megboyzz.lks.profile.domain.LocalDispatcherScope
import ru.megboyzz.lks.profile.domain.repositories.StudentRepository
import javax.inject.Inject
class GetAllFavoritesUseCase @Inject constructor(
private val studentRepository: StudentRepository,
@LocalDispatcherScope
private val coroutineDispatcher: CoroutineDispatcher
) {
suspend operator fun invoke() = withContext(coroutineDispatcher) { studentRepository.getAllFavStudents() }
}
@@ -1,20 +0,0 @@
package ru.megboyzz.lks.profile.domain.usecases.fav
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import ru.megboyzz.lks.profile.domain.LocalDispatcherScope
import ru.megboyzz.lks.profile.domain.entities.LksResponse
import ru.megboyzz.lks.profile.domain.repositories.StudentRepository
import javax.inject.Inject
class RemoveFavoriteUseCase @Inject constructor(
private val studentRepository: StudentRepository,
@LocalDispatcherScope
private val coroutineDispatcher: CoroutineDispatcher
) {
suspend operator fun invoke(lksResponse: LksResponse) = withContext(coroutineDispatcher) {
studentRepository.deleteFormFav(lksResponse)
}
}
@@ -1,4 +0,0 @@
package ru.megboyzz.lks.profile.domain.usecases.pages
class AddLatestDataSearchUseCase {
}
@@ -1,20 +0,0 @@
package ru.megboyzz.lks.profile.domain.usecases.pages
import kotlinx.coroutines.withContext
import ru.megboyzz.lks.profile.domain.NetworkDispatcherScope
import ru.megboyzz.lks.profile.domain.entities.LksRequest
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
class GetDataPage @Inject constructor(
private val lksRepository: LksRepository,
@NetworkDispatcherScope
private val coroutineContext: CoroutineContext
) {
suspend operator fun invoke(lksRequest: LksRequest, pageNumber: Int) = withContext(coroutineContext) {
//lksRepository.getPage(lksRequest, pageNumber)
}
}
@@ -1,4 +0,0 @@
package ru.megboyzz.lks.profile.domain.usecases.pages
class GetLatestDataSearchUseCase {
}
@@ -0,0 +1,32 @@
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.SignInScreenModel
@Module
@InstallIn(ActivityComponent::class)
interface HiltModule {
/*@Binds
@IntoMap
@ScreenModelKey(SignInScreenModel::class)
abstract fun bindSignInScreenModel(
signInScreenModel: SignInScreenModel
) : ScreenModel*/
@Binds
@IntoMap
@ScreenModelFactoryKey(SignInScreenModel.Factory::class)
fun bindSignInScreenModelFactory(
factory: SignInScreenModel.Factory
): ScreenModelFactory
}
@@ -0,0 +1,14 @@
package ru.megboyzz.lks.profile.ui.components
import android.provider.ContactsContract.Profile
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import ru.megboyzz.lks.profile.domain.entities.LksResponse
import ru.megboyzz.lks.profile.domain.entities.LksStudent
@Composable
fun ProfileCard(lksStudent: LksStudent) {
}
@@ -1,2 +0,0 @@
package ru.megboyzz.lks.profile.ui.components
@@ -1,8 +1,55 @@
package ru.megboyzz.lks.profile.ui.model
import cafe.adriel.voyager.core.model.ScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
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 javax.inject.Inject
class SearchScreenModel : ScreenModel {
class SearchScreenModel @Inject constructor(
private val lksRepository: LksRepository,
@DefaultCookies
private val cookies: Map<String, String>
) : ScreenModel {
private val _request = MutableStateFlow(LksRequest())
val request = _request.asStateFlow()
private val _curPageNumber = MutableStateFlow(1)
val curPageNumber = _curPageNumber.asStateFlow()
private val _responseList = MutableStateFlow(LksResponse())
val responseList = _responseList.asStateFlow()
init {
_curPageNumber.onEach {
update()
}
}
fun nextPage() = screenModelScope.launch { _curPageNumber.emit(_curPageNumber.value++) }
private fun update() = screenModelScope.launch {
val result = lksRepository.getPage(_request.value, cookies, curPageNumber.value)
val list = result.getOrElse { LksResponse() }
_responseList.emit(list)
}
fun newSearch() = screenModelScope.launch {
_curPageNumber.emit(1)
update()
}
@@ -1,23 +1,25 @@
package ru.megboyzz.lks.profile.ui.model
import androidx.compose.runtime.Immutable
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.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import ru.megboyzz.lks.profile.domain.repositories.LksRepository
import ru.megboyzz.lks.profile.ui.screens.SearchScreen
class SignInScreenModel(
class SignInScreenModel @AssistedInject constructor(
private val lksRepository: LksRepository,
private val navigator: Navigator
@Assisted private val navigator: Navigator
) : ScreenModel {
private val _username = MutableStateFlow("")
@@ -39,15 +41,14 @@ class SignInScreenModel(
init {
cookie = lksRepository.restoreCooke()
if(cookie.isNotEmpty()) {
navigator.push(SearchScreen())
screenModelScope.launch {
cookie = lksRepository.restoreCooke()
if(lksRepository.cookiesIsValid(cookie))
navigator.push(SearchScreen())
}
state.onEach {
if(it == SignInState.Success)
navigator.push(SearchScreen())
if(it == SignInState.Success) navigator.push(SearchScreen())
}.launchIn(screenModelScope)
}
@@ -73,4 +74,9 @@ class SignInScreenModel(
}
}
@AssistedFactory
interface Factory : ScreenModelFactory {
fun create(navigator: Navigator): SignInScreenModel
}
}
@@ -3,7 +3,9 @@ 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.material3.Text
@@ -13,28 +15,28 @@ import androidx.compose.ui.Modifier
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 ru.megboyzz.lks.profile.ui.model.SearchScreenModel
class SearchScreen : Screen {
@Composable
override fun Content() {
val screenModel = getScreenModel<SearchScreenModel>()
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
contentAlignment = Alignment.TopCenter
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Spacer(Modifier.height(20.dp))
val navigator = LocalNavigator.current!!
Text("Успех!")
OutlinedButton(
onClick = navigator::popUntilRoot
) {
Text("Вернуться")
}
}
}
@@ -1,7 +1,5 @@
package ru.megboyzz.lks.profile.ui.screens
import android.content.Context
import android.content.SharedPreferences
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -13,33 +11,23 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.hilt.getScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import ru.megboyzz.lks.profile.data.repositories.LksRepositoryImpl
import ru.megboyzz.lks.profile.ui.model.SignInScreenModel
import kotlin.math.log
class SignInScreen : Screen {
@Composable
override fun Content() {
val context = LocalContext.current
val navigator = LocalNavigator.current!!
val viewModel = rememberScreenModel {
val preferences = context.getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
SignInScreenModel(
lksRepository = LksRepositoryImpl(preferences),
navigator = navigator
)
val viewModel = getScreenModel<SignInScreenModel, SignInScreenModel.Factory> { assistedFactory ->
assistedFactory.create(navigator)
}
val username by viewModel.username.collectAsState()
+1 -1
View File
@@ -5,5 +5,5 @@ plugins {
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.jetbrains.kotlin.jvm) apply false
alias(libs.plugins.android.library) apply false
id("com.google.dagger.hilt.android") version "2.44" apply false
id("com.google.dagger.hilt.android") version "2.51.1" apply false
}
+3
View File
@@ -1,5 +1,6 @@
[versions]
agp = "8.5.1"
hiltAndroidCompiler = "2.51.1"
jsoup = "1.18.1"
kotlin = "2.0.0"
coreKtx = "1.13.1"
@@ -16,6 +17,8 @@ voyagerVersion = "1.1.0-beta02"
[libraries]
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-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroidCompiler" }
jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }