diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..5e30999 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +LKS PROFILE \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a07f134..e484071 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 31a2708..146a1f8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ = signInLks(username, password) + override suspend fun cookiesIsValid(cookie: Map): Boolean { + return true + } + override fun saveCookie(cookie: Map) { sharedPreferences.edit { diff --git a/app/src/main/java/ru/megboyzz/lks/profile/domain/Scopes.kt b/app/src/main/java/ru/megboyzz/lks/profile/domain/Scopes.kt index e294916..21b4a31 100644 --- a/app/src/main/java/ru/megboyzz/lks/profile/domain/Scopes.kt +++ b/app/src/main/java/ru/megboyzz/lks/profile/domain/Scopes.kt @@ -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 \ No newline at end of file +annotation class CookiesPrefs + +@Qualifier +annotation class DefaultCookies \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/domain/entities/LksRequest.kt b/app/src/main/java/ru/megboyzz/lks/profile/domain/entities/LksRequest.kt index baf8acc..771aae3 100644 --- a/app/src/main/java/ru/megboyzz/lks/profile/domain/entities/LksRequest.kt +++ b/app/src/main/java/ru/megboyzz/lks/profile/domain/entities/LksRequest.kt @@ -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? ... diff --git a/app/src/main/java/ru/megboyzz/lks/profile/domain/repositories/LksRepository.kt b/app/src/main/java/ru/megboyzz/lks/profile/domain/repositories/LksRepository.kt index d5b10b9..ddf8e4d 100644 --- a/app/src/main/java/ru/megboyzz/lks/profile/domain/repositories/LksRepository.kt +++ b/app/src/main/java/ru/megboyzz/lks/profile/domain/repositories/LksRepository.kt @@ -7,6 +7,8 @@ interface LksRepository { suspend fun signInAndGetCookies(username: String, password: String): Map + suspend fun cookiesIsValid(cookie: Map): Boolean + suspend fun getPage(lksRequest: LksRequest, cookie: Map, pageNumber: Int): Result fun saveCookie(cookie: Map) diff --git a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/SignInUseCase.kt b/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/SignInUseCase.kt deleted file mode 100644 index fd89aea..0000000 --- a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/SignInUseCase.kt +++ /dev/null @@ -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") - } - -} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/fav/AddFavoriteUseCase.kt b/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/fav/AddFavoriteUseCase.kt deleted file mode 100644 index 1ba679c..0000000 --- a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/fav/AddFavoriteUseCase.kt +++ /dev/null @@ -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) - } - -} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/fav/GetAllFavoritesUseCase.kt b/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/fav/GetAllFavoritesUseCase.kt deleted file mode 100644 index 5f4d1aa..0000000 --- a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/fav/GetAllFavoritesUseCase.kt +++ /dev/null @@ -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() } - -} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/fav/RemoveFavoriteUseCase.kt b/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/fav/RemoveFavoriteUseCase.kt deleted file mode 100644 index 8effc9f..0000000 --- a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/fav/RemoveFavoriteUseCase.kt +++ /dev/null @@ -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) - } - -} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/pages/AddLatestDataSearchUseCase.kt b/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/pages/AddLatestDataSearchUseCase.kt deleted file mode 100644 index 7c9a77d..0000000 --- a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/pages/AddLatestDataSearchUseCase.kt +++ /dev/null @@ -1,4 +0,0 @@ -package ru.megboyzz.lks.profile.domain.usecases.pages - -class AddLatestDataSearchUseCase { -} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/pages/GetDataPage.kt b/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/pages/GetDataPage.kt deleted file mode 100644 index 88128e7..0000000 --- a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/pages/GetDataPage.kt +++ /dev/null @@ -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) - } - -} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/pages/GetLatestDataSearchUseCase.kt b/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/pages/GetLatestDataSearchUseCase.kt deleted file mode 100644 index 631dbfa..0000000 --- a/app/src/main/java/ru/megboyzz/lks/profile/domain/usecases/pages/GetLatestDataSearchUseCase.kt +++ /dev/null @@ -1,4 +0,0 @@ -package ru.megboyzz.lks.profile.domain.usecases.pages - -class GetLatestDataSearchUseCase { -} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/ui/HiltModule.kt b/app/src/main/java/ru/megboyzz/lks/profile/ui/HiltModule.kt new file mode 100644 index 0000000..dadf8e7 --- /dev/null +++ b/app/src/main/java/ru/megboyzz/lks/profile/ui/HiltModule.kt @@ -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 + +} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/ui/components/SearchComponents.kt b/app/src/main/java/ru/megboyzz/lks/profile/ui/components/SearchComponents.kt new file mode 100644 index 0000000..a058271 --- /dev/null +++ b/app/src/main/java/ru/megboyzz/lks/profile/ui/components/SearchComponents.kt @@ -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) { + + + +} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/ui/components/SignInComponents.kt b/app/src/main/java/ru/megboyzz/lks/profile/ui/components/SignInComponents.kt deleted file mode 100644 index 4079edd..0000000 --- a/app/src/main/java/ru/megboyzz/lks/profile/ui/components/SignInComponents.kt +++ /dev/null @@ -1,2 +0,0 @@ -package ru.megboyzz.lks.profile.ui.components - diff --git a/app/src/main/java/ru/megboyzz/lks/profile/ui/model/SearchScreenModel.kt b/app/src/main/java/ru/megboyzz/lks/profile/ui/model/SearchScreenModel.kt index 683e89b..63a46a6 100644 --- a/app/src/main/java/ru/megboyzz/lks/profile/ui/model/SearchScreenModel.kt +++ b/app/src/main/java/ru/megboyzz/lks/profile/ui/model/SearchScreenModel.kt @@ -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 +) : 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() + + } diff --git a/app/src/main/java/ru/megboyzz/lks/profile/ui/model/SignInScreenModel.kt b/app/src/main/java/ru/megboyzz/lks/profile/ui/model/SignInScreenModel.kt index 116824e..e65a9d0 100644 --- a/app/src/main/java/ru/megboyzz/lks/profile/ui/model/SignInScreenModel.kt +++ b/app/src/main/java/ru/megboyzz/lks/profile/ui/model/SignInScreenModel.kt @@ -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 + } + } \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/lks/profile/ui/screens/SearchScreen.kt b/app/src/main/java/ru/megboyzz/lks/profile/ui/screens/SearchScreen.kt index 3f2f9f8..6037b43 100644 --- a/app/src/main/java/ru/megboyzz/lks/profile/ui/screens/SearchScreen.kt +++ b/app/src/main/java/ru/megboyzz/lks/profile/ui/screens/SearchScreen.kt @@ -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() + 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("Вернуться") - } + + } } diff --git a/app/src/main/java/ru/megboyzz/lks/profile/ui/screens/SignInScreen.kt b/app/src/main/java/ru/megboyzz/lks/profile/ui/screens/SignInScreen.kt index a238acd..83e92b5 100644 --- a/app/src/main/java/ru/megboyzz/lks/profile/ui/screens/SignInScreen.kt +++ b/app/src/main/java/ru/megboyzz/lks/profile/ui/screens/SignInScreen.kt @@ -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 { assistedFactory -> + assistedFactory.create(navigator) } val username by viewModel.username.collectAsState() diff --git a/build.gradle.kts b/build.gradle.kts index 5d68bde..cb4c2b2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -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 } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d883fd0..986e6f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" }