Стабильная аунтификация
This commit is contained in:
@@ -2,18 +2,18 @@ package ru.megboyzz.dnevnik
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import ru.megboyzz.dnevnik.db.CredentialsDataBase
|
import ru.megboyzz.dnevnik.db.AppDataBase
|
||||||
|
|
||||||
class App : Application() {
|
class App : Application() {
|
||||||
|
|
||||||
lateinit var database: CredentialsDataBase
|
lateinit var database: AppDataBase
|
||||||
private set
|
private set
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
|
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
instance = this
|
instance = this
|
||||||
database = Room.databaseBuilder(this, CredentialsDataBase::class.java, "database")
|
database = Room.databaseBuilder(this, AppDataBase::class.java, "database")
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Application
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material.Surface
|
import androidx.compose.material.Surface
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -52,10 +53,12 @@ class MainActivity : ComponentActivity() {
|
|||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
|
||||||
val credentialsDao = app.database.credentialsDao()
|
val credentialsDao = app.database.credentialsDao()
|
||||||
val credentials = credentialsDao.getCredentials()
|
|
||||||
if(!credentials.rememberMe)
|
|
||||||
credentialsDao.deleteCredentials()
|
|
||||||
|
|
||||||
|
if(credentialsDao.credentialsIsExists()) {
|
||||||
|
val credentials = credentialsDao.getCredentials()
|
||||||
|
if (!credentials.rememberMe)
|
||||||
|
credentialsDao.deleteCredentials()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,54 @@
|
|||||||
package ru.megboyzz.dnevnik.authorization
|
package ru.megboyzz.dnevnik.authorization
|
||||||
|
|
||||||
import android.util.Log
|
import com.google.gson.Gson
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import org.jsoup.Connection
|
import org.jsoup.Connection
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import ru.megboyzz.dnevnik.db.dao.CredentialsDao
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import ru.megboyzz.dnevnik.db.AppDataBase
|
||||||
|
import ru.megboyzz.dnevnik.entities.context.marks.init.state.MarksContext
|
||||||
|
import ru.megboyzz.dnevnik.entities.context.marks.init.state.SchoolType
|
||||||
import ru.megboyzz.dnevnik.entities.db.Credentials
|
import ru.megboyzz.dnevnik.entities.db.Credentials
|
||||||
|
import ru.megboyzz.dnevnik.entities.db.GlobalUserContext
|
||||||
|
import ru.megboyzz.dnevnik.service.ContextService
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
|
|
||||||
class AuthorizationManager(private val credentialsDao: CredentialsDao) {
|
class AuthorizationManager(dataBase: AppDataBase) {
|
||||||
|
|
||||||
private val returnUrl =
|
private val returnUrl =
|
||||||
"https://login.dnevnik.ru/oauth2?response_type=token&client_id=bb97b3e445a340b9b9cab4b9ea0dbd6f&scope=CommonInfo,ContactInfo,FriendsAndRelatives,EducationalInfo"
|
"https://login.dnevnik.ru/oauth2?response_type=token&client_id=bb97b3e445a340b9b9cab4b9ea0dbd6f&scope=CommonInfo,ContactInfo,FriendsAndRelatives,EducationalInfo"
|
||||||
|
|
||||||
private val baseUrl = "https://login.dnevnik.ru/login/"
|
private val baseUrl = "https://login.dnevnik.ru/login/"
|
||||||
|
|
||||||
|
private val apiUrl = "https://api.dnevnik.ru"
|
||||||
|
|
||||||
|
private val retrofit = Retrofit
|
||||||
|
.Builder()
|
||||||
|
.baseUrl(apiUrl)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
private val contextService = retrofit.create(ContextService::class.java)
|
||||||
|
|
||||||
|
private val marksState = "https://dnevnik.ru/marks"
|
||||||
|
|
||||||
|
private val credentialsDao = dataBase.credentialsDao()
|
||||||
|
|
||||||
|
private val userContextDao = dataBase.globalUserContextDao()
|
||||||
|
|
||||||
private var credentials = Credentials(token = "", cookies = mapOf(), rememberMe = false)
|
private var credentials = Credentials(token = "", cookies = mapOf(), rememberMe = false)
|
||||||
|
|
||||||
|
private val gson = Gson()
|
||||||
|
|
||||||
fun login(
|
fun login(
|
||||||
login: String,
|
login: String,
|
||||||
password: String,
|
password: String,
|
||||||
rememberMe: Boolean
|
rememberMe: Boolean
|
||||||
): AuthorizationStatus {
|
): AuthorizationStatus {
|
||||||
|
|
||||||
val execute = runCatching<Connection.Response> {
|
runCatching<Connection.Response> {
|
||||||
Jsoup
|
Jsoup
|
||||||
.connect(baseUrl)
|
.connect(baseUrl)
|
||||||
.method(Connection.Method.POST)
|
.method(Connection.Method.POST)
|
||||||
@@ -34,26 +58,15 @@ class AuthorizationManager(private val credentialsDao: CredentialsDao) {
|
|||||||
.followRedirects(true)
|
.followRedirects(true)
|
||||||
.execute()
|
.execute()
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
|
|
||||||
Log.i("AuthorizationManager", "No internet")
|
|
||||||
return AuthorizationStatus.NO_INTERNET
|
return AuthorizationStatus.NO_INTERNET
|
||||||
}
|
}.onSuccess { response ->
|
||||||
|
if(response.statusCode() != 200)
|
||||||
val response = execute.getOrNull()
|
|
||||||
|
|
||||||
if(response != null){
|
|
||||||
|
|
||||||
if(response.statusCode() != 200) {
|
|
||||||
Log.i("AuthorizationManager", "Maintain")
|
|
||||||
return AuthorizationStatus.MAINTAIN
|
return AuthorizationStatus.MAINTAIN
|
||||||
}
|
|
||||||
|
|
||||||
val url = response.url()
|
val url = response.url()
|
||||||
|
|
||||||
if(url.getResult() != "success") {
|
if(url.getResult() != "success")
|
||||||
Log.i("AuthorizationManager", "Wrong login")
|
|
||||||
return AuthorizationStatus.WRONG_CREDENTIALS
|
return AuthorizationStatus.WRONG_CREDENTIALS
|
||||||
}
|
|
||||||
|
|
||||||
//Безопасная зона
|
//Безопасная зона
|
||||||
val cookies = response.cookies()
|
val cookies = response.cookies()
|
||||||
@@ -64,7 +77,39 @@ class AuthorizationManager(private val credentialsDao: CredentialsDao) {
|
|||||||
)
|
)
|
||||||
dbUpdate()
|
dbUpdate()
|
||||||
|
|
||||||
}else return AuthorizationStatus.NO_INTERNET //Может быть опасно
|
kotlin.runCatching {
|
||||||
|
|
||||||
|
Jsoup
|
||||||
|
.connect(marksState)
|
||||||
|
.method(Connection.Method.GET)
|
||||||
|
.cookies(cookies)
|
||||||
|
.ignoreContentType(true)
|
||||||
|
.followRedirects(true)
|
||||||
|
.execute()
|
||||||
|
|
||||||
|
}.onFailure {
|
||||||
|
return AuthorizationStatus.NO_INTERNET
|
||||||
|
}.onSuccess { response1 ->
|
||||||
|
val htmlByLines = response1.body().split("\n")
|
||||||
|
val contextLine = htmlByLines.find { it.contains("window.__MARKS__INITIAL__STATE__") }
|
||||||
|
val marksContextStr =
|
||||||
|
contextLine?.substring(contextLine.indexOf("{"), contextLine.length - 2)
|
||||||
|
val marksContext = gson.fromJson(marksContextStr, MarksContext::class.java)
|
||||||
|
|
||||||
|
val context = contextService.getContext(credentials.token, marksContext.context.userId).execute()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(context.isSuccessful){
|
||||||
|
val body = context.body() ?: return AuthorizationStatus.UNKNOWN_ERROR
|
||||||
|
userContextDao.setGlobalUserContext(GlobalUserContext(
|
||||||
|
apiUserContext = body,
|
||||||
|
marksInitStateUserContext = marksContext
|
||||||
|
))
|
||||||
|
} else return AuthorizationStatus.UNKNOWN_ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return AuthorizationStatus.LOGGED
|
return AuthorizationStatus.LOGGED
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ enum class AuthorizationStatus {
|
|||||||
WRONG_CREDENTIALS,
|
WRONG_CREDENTIALS,
|
||||||
NO_INTERNET,
|
NO_INTERNET,
|
||||||
MAINTAIN,
|
MAINTAIN,
|
||||||
NOTHING
|
CREDENTIALS_LOADING,
|
||||||
|
NOTHING,
|
||||||
|
UNKNOWN_ERROR
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package ru.megboyzz.dnevnik.db
|
||||||
|
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import ru.megboyzz.dnevnik.db.dao.CredentialsDao
|
||||||
|
import ru.megboyzz.dnevnik.db.dao.GlobalUserContextDao
|
||||||
|
import ru.megboyzz.dnevnik.entities.db.Credentials
|
||||||
|
import ru.megboyzz.dnevnik.entities.db.GlobalUserContext
|
||||||
|
|
||||||
|
@Database(
|
||||||
|
entities = [Credentials::class, GlobalUserContext::class],
|
||||||
|
version = 1
|
||||||
|
)
|
||||||
|
abstract class AppDataBase: RoomDatabase() {
|
||||||
|
|
||||||
|
abstract fun credentialsDao(): CredentialsDao
|
||||||
|
abstract fun globalUserContextDao(): GlobalUserContextDao
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package ru.megboyzz.dnevnik.db
|
|
||||||
|
|
||||||
import androidx.room.Database
|
|
||||||
import androidx.room.RoomDatabase
|
|
||||||
import ru.megboyzz.dnevnik.db.dao.CredentialsDao
|
|
||||||
import ru.megboyzz.dnevnik.entities.db.Credentials
|
|
||||||
|
|
||||||
@Database(
|
|
||||||
entities = [Credentials::class],
|
|
||||||
version = 1
|
|
||||||
)
|
|
||||||
abstract class CredentialsDataBase: RoomDatabase() {
|
|
||||||
|
|
||||||
abstract fun credentialsDao(): CredentialsDao
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package ru.megboyzz.dnevnik.db.converters
|
||||||
|
|
||||||
|
import androidx.room.TypeConverter
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import ru.megboyzz.dnevnik.entities.context.marks.init.state.MarksContext
|
||||||
|
import ru.megboyzz.dnevnik.entities.response.UserContext
|
||||||
|
|
||||||
|
class DataStructureConverter {
|
||||||
|
|
||||||
|
val gson = Gson()
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromUserContext(userContext: UserContext): String = gson.toJson(userContext)
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toUserContext(savedUserContext: String): UserContext = gson.fromJson(savedUserContext, UserContext::class.java)
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromMarksContext(marksContext: MarksContext): String = gson.toJson(marksContext)
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toMarksContext(savedMarksContext: String): MarksContext = gson.fromJson(savedMarksContext, MarksContext::class.java)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,7 +10,6 @@ import ru.megboyzz.dnevnik.entities.db.Credentials
|
|||||||
@Dao
|
@Dao
|
||||||
interface CredentialsDao {
|
interface CredentialsDao {
|
||||||
|
|
||||||
|
|
||||||
@Query("SELECT EXISTS(SELECT * FROM Credentials WHERE id = 0)")
|
@Query("SELECT EXISTS(SELECT * FROM Credentials WHERE id = 0)")
|
||||||
fun credentialsIsExists(): Boolean
|
fun credentialsIsExists(): Boolean
|
||||||
@Query("SELECT * FROM Credentials WHERE id = 0")
|
@Query("SELECT * FROM Credentials WHERE id = 0")
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package ru.megboyzz.dnevnik.db.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import ru.megboyzz.dnevnik.entities.db.GlobalUserContext
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface GlobalUserContextDao {
|
||||||
|
|
||||||
|
@Query("SELECT EXISTS(SELECT * FROM GlobalUserContext WHERE id = 0)")
|
||||||
|
fun globalUserContextIsExists(): Boolean
|
||||||
|
|
||||||
|
@Query("SELECT * FROM GlobalUserContext WHERE id = 0")
|
||||||
|
fun getGlobalUserContext(): GlobalUserContext
|
||||||
|
|
||||||
|
@Query("DELETE FROM GlobalUserContext WHERE id = 0")
|
||||||
|
fun deleteGlobalUserContext()
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
fun setGlobalUserContext(profile: GlobalUserContext)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package ru.megboyzz.dnevnik.entities.context
|
||||||
|
|
||||||
|
enum class GroupType {
|
||||||
|
Quarter
|
||||||
|
}
|
||||||
@@ -2,6 +2,6 @@ package ru.megboyzz.dnevnik.entities.context
|
|||||||
|
|
||||||
data class PeriodGroup(
|
data class PeriodGroup(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val type: String, //Обычно равен "Quarter", то есть Четверть, но как будет семестр у них????
|
val type: GroupType, //Обычно равен "Quarter", то есть Четверть, но как будет семестр у них????
|
||||||
val periods: List<PeriodInfo>
|
val periods: List<PeriodInfo>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package ru.megboyzz.dnevnik.entities.context
|
|||||||
data class PeriodInfo(
|
data class PeriodInfo(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val number: Short,
|
val number: Short,
|
||||||
val type: String,
|
val type: GroupType,
|
||||||
val dateStart: Long,
|
val dateStart: Long,
|
||||||
val dateFinish: Long,
|
val dateFinish: Long,
|
||||||
val studyYear: Short,
|
val studyYear: Short,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ data class PersonContext(
|
|||||||
val middleName: String,
|
val middleName: String,
|
||||||
val lastName: String,
|
val lastName: String,
|
||||||
val avatarUrl: String,
|
val avatarUrl: String,
|
||||||
val schoolInfo: SchoolInfo,
|
val school: SchoolInfo,
|
||||||
val group: GroupInfo,
|
val group: GroupInfo,
|
||||||
val reportingPeriodGroup: PeriodGroup
|
val reportingPeriodGroup: PeriodGroup
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,5 +3,6 @@ package ru.megboyzz.dnevnik.entities.context
|
|||||||
data class SchoolInfo(
|
data class SchoolInfo(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val name: String,
|
val name: String,
|
||||||
val avatarUrl: String
|
val avatarUrl: String,
|
||||||
|
val type: SchoolType
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package ru.megboyzz.dnevnik.entities.context
|
||||||
|
|
||||||
|
enum class SchoolType {
|
||||||
|
Additional,
|
||||||
|
Regular
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package ru.megboyzz.dnevnik.entities.context.marks.init.state
|
||||||
|
|
||||||
|
data class Group(
|
||||||
|
val groupId: String,
|
||||||
|
val groupName: String,
|
||||||
|
val reportingPeriodNotSet: Boolean,
|
||||||
|
val periodTabName: String
|
||||||
|
)
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package ru.megboyzz.dnevnik.entities.context.marks.init.state
|
||||||
|
|
||||||
|
data class GroupHistorical(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val studyYear: Int,
|
||||||
|
val periods: List<Period>,
|
||||||
|
val periodTabName: String
|
||||||
|
)
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package ru.megboyzz.dnevnik.entities.context.marks.init.state
|
||||||
|
|
||||||
|
data class MarksContext(
|
||||||
|
val apiUrl: String,
|
||||||
|
val context: UserContext
|
||||||
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package ru.megboyzz.dnevnik.entities.context.marks.init.state
|
||||||
|
|
||||||
|
data class Period(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val shortName: String,
|
||||||
|
val number: Int,
|
||||||
|
val isDefault: Boolean
|
||||||
|
)
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package ru.megboyzz.dnevnik.entities.context.marks.init.state
|
||||||
|
|
||||||
|
data class SchoolMembership(
|
||||||
|
val personId: String,
|
||||||
|
val firstName: String,
|
||||||
|
val lastName: String,
|
||||||
|
val avatarUrl: String,
|
||||||
|
val schoolId: String,
|
||||||
|
val schoolName: String,
|
||||||
|
val isOdo: Boolean,
|
||||||
|
val isTermReportEnabled: Boolean,
|
||||||
|
val studyYear: Int,
|
||||||
|
val schoolType: SchoolType,
|
||||||
|
val groups: List<Group>,
|
||||||
|
val holidays: List<String>,
|
||||||
|
val groupHistory: List<GroupHistorical>
|
||||||
|
)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package ru.megboyzz.dnevnik.entities.context.marks.init.state
|
||||||
|
|
||||||
|
enum class SchoolType {
|
||||||
|
|
||||||
|
Regular,
|
||||||
|
Additional
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package ru.megboyzz.dnevnik.entities.context.marks.init.state
|
||||||
|
|
||||||
|
|
||||||
|
data class UserContext(
|
||||||
|
val userId: String,
|
||||||
|
val role: String,
|
||||||
|
val schoolMemberships: List<SchoolMembership>,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package ru.megboyzz.dnevnik.entities.db
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import androidx.room.TypeConverters
|
||||||
|
import ru.megboyzz.dnevnik.db.converters.DataStructureConverter
|
||||||
|
import ru.megboyzz.dnevnik.entities.context.marks.init.state.MarksContext
|
||||||
|
import ru.megboyzz.dnevnik.entities.response.UserContext
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@TypeConverters(DataStructureConverter::class)
|
||||||
|
data class GlobalUserContext(
|
||||||
|
@PrimaryKey
|
||||||
|
val id: Int = 0,
|
||||||
|
val apiUserContext: UserContext, // Обычный контекст из API
|
||||||
|
val marksInitStateUserContext: MarksContext //window.__MARKS__INITIAL__STATE__
|
||||||
|
)
|
||||||
@@ -3,6 +3,7 @@ package ru.megboyzz.dnevnik.entities.response
|
|||||||
import ru.megboyzz.dnevnik.entities.context.PersonContext
|
import ru.megboyzz.dnevnik.entities.context.PersonContext
|
||||||
import ru.megboyzz.dnevnik.entities.context.UserInfo
|
import ru.megboyzz.dnevnik.entities.context.UserInfo
|
||||||
|
|
||||||
|
|
||||||
data class UserContext(
|
data class UserContext(
|
||||||
val info: UserInfo,
|
val info: UserInfo,
|
||||||
val contextPersons: List<PersonContext>
|
val contextPersons: List<PersonContext>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.megboyzz.dnevnik.navigation
|
package ru.megboyzz.dnevnik.navigation
|
||||||
|
|
||||||
|
import androidx.compose.material.CircularProgressIndicator
|
||||||
import androidx.compose.material.rememberScaffoldState
|
import androidx.compose.material.rememberScaffoldState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -18,6 +19,7 @@ import ru.megboyzz.dnevnik.collectAsMutableState
|
|||||||
import ru.megboyzz.dnevnik.screens.*
|
import ru.megboyzz.dnevnik.screens.*
|
||||||
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel
|
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel
|
||||||
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModelFactory
|
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModelFactory
|
||||||
|
import ru.megboyzz.dnevnik.navigate
|
||||||
|
|
||||||
sealed class BaseNavRote(open val route: String)
|
sealed class BaseNavRote(open val route: String)
|
||||||
|
|
||||||
@@ -52,11 +54,18 @@ fun AppNavHost(){
|
|||||||
){
|
){
|
||||||
composable(AppNavRoute.Splash.route) {
|
composable(AppNavRoute.Splash.route) {
|
||||||
|
|
||||||
if(loginStatus.value != AuthorizationStatus.LOGGED){
|
when(loginStatus.value){
|
||||||
navController.navigate(AppNavRoute.Login.route)
|
|
||||||
}else
|
|
||||||
navController.navigate(AppNavRoute.Marks.route)
|
|
||||||
|
|
||||||
|
AuthorizationStatus.CREDENTIALS_LOADING -> { CircularProgressIndicator() }
|
||||||
|
AuthorizationStatus.LOGGED -> {
|
||||||
|
navController.navigate(AppNavRoute.Marks)
|
||||||
|
}
|
||||||
|
AuthorizationStatus.NOTHING -> {
|
||||||
|
navController.navigate(AppNavRoute.Login)
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
composable(AppNavRoute.Login.route) { LoginScreen(navController) }
|
composable(AppNavRoute.Login.route) { LoginScreen(navController) }
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import androidx.navigation.NavController
|
|||||||
import ru.megboyzz.dnevnik.MainActivity
|
import ru.megboyzz.dnevnik.MainActivity
|
||||||
import ru.megboyzz.dnevnik.authorization.AuthorizationStatus
|
import ru.megboyzz.dnevnik.authorization.AuthorizationStatus
|
||||||
import ru.megboyzz.dnevnik.collectAsMutableState
|
import ru.megboyzz.dnevnik.collectAsMutableState
|
||||||
|
import ru.megboyzz.dnevnik.navigate
|
||||||
import ru.megboyzz.dnevnik.navigation.AppNavRoute
|
import ru.megboyzz.dnevnik.navigation.AppNavRoute
|
||||||
import ru.megboyzz.dnevnik.screens.ui.AlertMessageBox
|
import ru.megboyzz.dnevnik.screens.ui.AlertMessageBox
|
||||||
import ru.megboyzz.dnevnik.screens.ui.LoginScreenContent
|
import ru.megboyzz.dnevnik.screens.ui.LoginScreenContent
|
||||||
@@ -35,6 +36,12 @@ fun LoginScreen(navController: NavController) {
|
|||||||
mutableStateOf(true)
|
mutableStateOf(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isLoading by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(loginStatus.value == AuthorizationStatus.LOGGING) isLoading = true
|
||||||
|
|
||||||
if(loginStatus.value == AuthorizationStatus.WRONG_CREDENTIALS && isError) {
|
if(loginStatus.value == AuthorizationStatus.WRONG_CREDENTIALS && isError) {
|
||||||
AlertMessageBox(
|
AlertMessageBox(
|
||||||
title = "Информация",
|
title = "Информация",
|
||||||
@@ -44,7 +51,7 @@ fun LoginScreen(navController: NavController) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(loginStatus.value == AuthorizationStatus.LOGGED)
|
if(loginStatus.value == AuthorizationStatus.LOGGED)
|
||||||
navController.navigate(AppNavRoute.Marks.route)
|
navController.navigate(AppNavRoute.Marks)
|
||||||
|
|
||||||
LoginScreenContent(
|
LoginScreenContent(
|
||||||
login = login.value,
|
login = login.value,
|
||||||
@@ -56,7 +63,7 @@ fun LoginScreen(navController: NavController) {
|
|||||||
isError = loginStatus.value == AuthorizationStatus.WRONG_CREDENTIALS,
|
isError = loginStatus.value == AuthorizationStatus.WRONG_CREDENTIALS,
|
||||||
onErrorChange = { },
|
onErrorChange = { },
|
||||||
|
|
||||||
isLoading = loginStatus.value == AuthorizationStatus.LOGGING,
|
isLoading = isLoading,
|
||||||
|
|
||||||
isRememberMe = rememberMe.value,
|
isRememberMe = rememberMe.value,
|
||||||
onRememberChange = { rememberMe.value = it },
|
onRememberChange = { rememberMe.value = it },
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.megboyzz.dnevnik.screens.ui
|
package ru.megboyzz.dnevnik.screens.ui
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
import androidx.compose.animation.*
|
import androidx.compose.animation.*
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
@@ -8,6 +9,7 @@ import androidx.compose.foundation.lazy.grid.GridCells
|
|||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
import androidx.compose.foundation.lazy.grid.items
|
import androidx.compose.foundation.lazy.grid.items
|
||||||
import androidx.compose.foundation.selection.toggleable
|
import androidx.compose.foundation.selection.toggleable
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
@@ -20,11 +22,13 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.clipToBounds
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.focus.onFocusChanged
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.*
|
import androidx.compose.ui.graphics.*
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.semantics.Role
|
import androidx.compose.ui.semantics.Role
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
@@ -33,9 +37,11 @@ import androidx.compose.ui.text.input.VisualTransformation
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.*
|
import androidx.compose.ui.unit.*
|
||||||
|
import coil.compose.AsyncImage
|
||||||
import ru.megboyzz.dnevnik.*
|
import ru.megboyzz.dnevnik.*
|
||||||
import ru.megboyzz.dnevnik.R
|
import ru.megboyzz.dnevnik.R
|
||||||
import ru.megboyzz.dnevnik.ui.theme.*
|
import ru.megboyzz.dnevnik.ui.theme.*
|
||||||
|
import ru.megboyzz.dnevnik.viewmodel.model.UserProfileModel
|
||||||
|
|
||||||
|
|
||||||
//Рефакторинг компонентов: разбиение файла с компонентами на отдельные файлы
|
//Рефакторинг компонентов: разбиение файла с компонентами на отдельные файлы
|
||||||
@@ -73,25 +79,29 @@ fun AlmostOutlinedText(
|
|||||||
@Composable
|
@Composable
|
||||||
fun ProfileCard(
|
fun ProfileCard(
|
||||||
textColor: Color = white,
|
textColor: Color = white,
|
||||||
painter: Painter
|
userProfileModel: UserProfileModel
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.Start
|
horizontalArrangement = Arrangement.Start
|
||||||
) {
|
) {
|
||||||
Image(
|
AsyncImage(
|
||||||
modifier = Modifier.padding(10.dp, 15.dp, 20.dp, 15.dp),
|
modifier = Modifier
|
||||||
painter = painter, //TODO заменить динмической картинкой
|
.padding(10.dp, 15.dp, 20.dp, 15.dp)
|
||||||
contentDescription = "chel"
|
.clip(RoundedCornerShape(25.dp))
|
||||||
|
.size(50.dp),
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
model = userProfileModel.avatarUrl,
|
||||||
|
contentDescription = ""
|
||||||
)
|
)
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(5.dp)) {
|
Column(verticalArrangement = Arrangement.spacedBy(5.dp)) {
|
||||||
Text(
|
Text(
|
||||||
text = "Имя и фамилия",
|
text = userProfileModel.toString(),
|
||||||
style = H1,
|
style = H1,
|
||||||
color = textColor
|
color = textColor
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "Класс/Группа",
|
text = userProfileModel.groupName,
|
||||||
style = H1,
|
style = H1,
|
||||||
color = textColor
|
color = textColor
|
||||||
)
|
)
|
||||||
@@ -640,3 +650,65 @@ fun AlertMessageBox(
|
|||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LeaveAlert(
|
||||||
|
isLoading: Boolean = false,
|
||||||
|
onAgree: () -> Unit,
|
||||||
|
onCancel: () -> Unit,
|
||||||
|
){
|
||||||
|
BaseAlertBox(
|
||||||
|
title = R.string.tile_leave.AsString(),
|
||||||
|
onDismissRequest = onCancel,
|
||||||
|
content = {
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||||
|
Text(
|
||||||
|
text = R.string.text_leave.AsString(),
|
||||||
|
style = H2,
|
||||||
|
color = dark
|
||||||
|
)
|
||||||
|
if(isLoading) CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buttons = {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
AlertButton(
|
||||||
|
title = R.string.title_cancel.AsString(),
|
||||||
|
onClick = onCancel
|
||||||
|
)
|
||||||
|
SpacerWidth(width = 10.dp)
|
||||||
|
AlertButton(
|
||||||
|
title = R.string.title_button_leave.AsString(),
|
||||||
|
onClick = onAgree
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AlertButton(
|
||||||
|
title: String,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
backgroundColor = mainBlue,
|
||||||
|
contentColor = white
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(bottom = 30.dp)
|
||||||
|
){
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = H1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -392,4 +392,13 @@ fun Test1() {
|
|||||||
onClick = { /*TODO*/ }
|
onClick = { /*TODO*/ }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun AlertTest() {
|
||||||
|
LeaveAlert(onAgree = { /*TODO*/ }) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,12 +5,8 @@ import androidx.compose.foundation.Image
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.Divider
|
import androidx.compose.material.*
|
||||||
import androidx.compose.material.ScaffoldState
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.material.Surface
|
|
||||||
import androidx.compose.material.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@@ -20,24 +16,34 @@ import androidx.compose.ui.geometry.Rect
|
|||||||
import androidx.compose.ui.geometry.RoundRect
|
import androidx.compose.ui.geometry.RoundRect
|
||||||
import androidx.compose.ui.geometry.Size
|
import androidx.compose.ui.geometry.Size
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import androidx.compose.ui.graphics.Outline
|
import androidx.compose.ui.graphics.Outline
|
||||||
import androidx.compose.ui.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.imageResource
|
||||||
import androidx.compose.ui.unit.Density
|
import androidx.compose.ui.unit.Density
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.megboyzz.dnevnik.*
|
import ru.megboyzz.dnevnik.*
|
||||||
import ru.megboyzz.dnevnik.R
|
import ru.megboyzz.dnevnik.R
|
||||||
import ru.megboyzz.dnevnik.navigation.AppNavRoute
|
import ru.megboyzz.dnevnik.navigation.AppNavRoute
|
||||||
import ru.megboyzz.dnevnik.screens.ui.AlmostOutlinedText
|
import ru.megboyzz.dnevnik.screens.ui.AlmostOutlinedText
|
||||||
|
import ru.megboyzz.dnevnik.screens.ui.LeaveAlert
|
||||||
import ru.megboyzz.dnevnik.screens.ui.ProfileCard
|
import ru.megboyzz.dnevnik.screens.ui.ProfileCard
|
||||||
import ru.megboyzz.dnevnik.ui.theme.H2
|
import ru.megboyzz.dnevnik.ui.theme.H2
|
||||||
import ru.megboyzz.dnevnik.ui.theme.Shapes
|
import ru.megboyzz.dnevnik.ui.theme.Shapes
|
||||||
import ru.megboyzz.dnevnik.ui.theme.mainBlue
|
import ru.megboyzz.dnevnik.ui.theme.mainBlue
|
||||||
import ru.megboyzz.dnevnik.ui.theme.white
|
import ru.megboyzz.dnevnik.ui.theme.white
|
||||||
|
import ru.megboyzz.dnevnik.viewmodel.ProfileViewModel
|
||||||
|
import ru.megboyzz.dnevnik.viewmodel.ProfileViewModelFactory
|
||||||
|
import ru.megboyzz.dnevnik.viewmodel.model.UserProfileModel
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -77,7 +83,43 @@ fun DrawerContent(
|
|||||||
scaffoldState: ScaffoldState
|
scaffoldState: ScaffoldState
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
val app = (LocalContext.current as MainActivity).app
|
||||||
|
|
||||||
|
val profileViewModel: ProfileViewModel = viewModel(
|
||||||
|
factory = ProfileViewModelFactory(app)
|
||||||
|
)
|
||||||
|
|
||||||
|
val profile = profileViewModel.profile.collectAsState()
|
||||||
|
|
||||||
|
val dao = app.database.credentialsDao()
|
||||||
|
|
||||||
|
|
||||||
|
var leaveAlertIsOpened by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isLeavingProcess by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
if(leaveAlertIsOpened){
|
||||||
|
LeaveAlert(
|
||||||
|
isLoading = isLeavingProcess,
|
||||||
|
onAgree = {
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
isLeavingProcess = true
|
||||||
|
dao.deleteCredentials()
|
||||||
|
leaveAlertIsOpened = false
|
||||||
|
this.launch(Dispatchers.Main) { navController.navigate(AppNavRoute.Login) }
|
||||||
|
scaffoldState.drawerState.close()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCancel = { leaveAlertIsOpened = false }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
NiceContainerForDrawer {
|
NiceContainerForDrawer {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -88,9 +130,20 @@ fun DrawerContent(
|
|||||||
horizontalAlignment = Alignment.Start,
|
horizontalAlignment = Alignment.Start,
|
||||||
) {
|
) {
|
||||||
SpacerHeight(10.dp)
|
SpacerHeight(10.dp)
|
||||||
ProfileCard(painter = R.drawable.ic_author.AsPainter())
|
if(profile.value == null)
|
||||||
|
CircularProgressIndicator()
|
||||||
|
else
|
||||||
|
ProfileCard(userProfileModel = profile.value!!)
|
||||||
SpacerHeight(15.dp)
|
SpacerHeight(15.dp)
|
||||||
AlmostOutlinedText(text = "Идет 3-я четверть")
|
if(profile.value == null)
|
||||||
|
CircularProgressIndicator()
|
||||||
|
else
|
||||||
|
AlmostOutlinedText(
|
||||||
|
text = if(profile.value!!.isTerm)
|
||||||
|
String.format(R.string.title_quatter_format.AsString(), profile.value!!.term)
|
||||||
|
else
|
||||||
|
String.format(R.string.title_sem_format.AsString(), profile.value!!.term)
|
||||||
|
)
|
||||||
SpacerHeight(20.dp)
|
SpacerHeight(20.dp)
|
||||||
Column(
|
Column(
|
||||||
verticalArrangement = Arrangement.spacedBy(5.dp),
|
verticalArrangement = Arrangement.spacedBy(5.dp),
|
||||||
@@ -135,7 +188,9 @@ fun DrawerContent(
|
|||||||
DrawerMainButton(
|
DrawerMainButton(
|
||||||
icon = R.drawable.ic_exit.AsPainter(),
|
icon = R.drawable.ic_exit.AsPainter(),
|
||||||
text = R.string.title_leave_from_acconut.AsString()
|
text = R.string.title_leave_from_acconut.AsString()
|
||||||
) { /* TODO */ }
|
) {
|
||||||
|
leaveAlertIsOpened = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
package ru.megboyzz.dnevnik.screens.ui.main
|
package ru.megboyzz.dnevnik.screens.ui.main
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
@@ -25,6 +22,7 @@ import ru.megboyzz.dnevnik.SpacerWidth
|
|||||||
import ru.megboyzz.dnevnik.ui.theme.mainBlue
|
import ru.megboyzz.dnevnik.ui.theme.mainBlue
|
||||||
import ru.megboyzz.dnevnik.ui.theme.white
|
import ru.megboyzz.dnevnik.ui.theme.white
|
||||||
import ru.megboyzz.dnevnik.R
|
import ru.megboyzz.dnevnik.R
|
||||||
|
import ru.megboyzz.dnevnik.viewmodel.model.UserProfileModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MainScaffold(
|
fun MainScaffold(
|
||||||
@@ -32,7 +30,7 @@ fun MainScaffold(
|
|||||||
title: String,
|
title: String,
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
scaffoldState: ScaffoldState,
|
scaffoldState: ScaffoldState,
|
||||||
content: (@Composable (it: PaddingValues) -> Unit),
|
content: @Composable (PaddingValues) -> Unit,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
@@ -52,6 +50,9 @@ fun MainScaffold(
|
|||||||
navController = navController,
|
navController = navController,
|
||||||
scaffoldState = scaffoldState,
|
scaffoldState = scaffoldState,
|
||||||
bottomBar = { BottomBar(navController) },
|
bottomBar = { BottomBar(navController) },
|
||||||
|
drawerContent = {
|
||||||
|
DrawerContent(navController, scaffoldState)
|
||||||
|
},
|
||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -65,6 +66,7 @@ fun BaseScaffold(
|
|||||||
navController: NavController,
|
navController: NavController,
|
||||||
scaffoldState: ScaffoldState,
|
scaffoldState: ScaffoldState,
|
||||||
bottomBar: @Composable () -> Unit,
|
bottomBar: @Composable () -> Unit,
|
||||||
|
drawerContent: @Composable (ColumnScope) -> Unit = {},
|
||||||
content: (@Composable (it: PaddingValues) -> Unit),
|
content: (@Composable (it: PaddingValues) -> Unit),
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -100,9 +102,7 @@ fun BaseScaffold(
|
|||||||
drawerContentColor = Color.Transparent,
|
drawerContentColor = Color.Transparent,
|
||||||
//drawerShape = drawerShape,
|
//drawerShape = drawerShape,
|
||||||
drawerElevation = 0.dp,
|
drawerElevation = 0.dp,
|
||||||
drawerContent = {
|
drawerContent = drawerContent,
|
||||||
DrawerContent(navController, scaffoldState)
|
|
||||||
},
|
|
||||||
bottomBar = bottomBar
|
bottomBar = bottomBar
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package ru.megboyzz.dnevnik.service
|
||||||
|
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.http.*
|
||||||
|
import ru.megboyzz.dnevnik.entities.response.UserContext
|
||||||
|
|
||||||
|
interface ContextService{
|
||||||
|
|
||||||
|
@GET("/mobile/v4/users/{personId}/context")
|
||||||
|
fun getContext(@Header("Access-Token") accessToken: String, @Path("personId") personId: String): Call<UserContext>
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package ru.megboyzz.dnevnik.service
|
|
||||||
|
|
||||||
|
|
||||||
import okhttp3.ResponseBody
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import retrofit2.http.POST
|
|
||||||
import retrofit2.http.Query
|
|
||||||
|
|
||||||
interface TokenService{
|
|
||||||
|
|
||||||
@POST("/")
|
|
||||||
suspend fun getToken(
|
|
||||||
@Query("login") login: String,
|
|
||||||
@Query("password") password: String,
|
|
||||||
@Query("ReturnUrl") returnUrl: String = "https://login.dnevnik.ru/oauth2?response_type=token&client_id=bb97b3e445a340b9b9cab4b9ea0dbd6f&scope=CommonInfo,ContactInfo,FriendsAndRelatives,EducationalInfo"
|
|
||||||
): retrofit2.Call<ResponseBody>
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -19,8 +19,8 @@ class AuthorizationViewModel(application: App) : AndroidViewModel(application) {
|
|||||||
val password = MutableStateFlow("")
|
val password = MutableStateFlow("")
|
||||||
val rememberMe = MutableStateFlow(false)
|
val rememberMe = MutableStateFlow(false)
|
||||||
|
|
||||||
val loginStatus = MutableStateFlow(AuthorizationStatus.NOTHING)
|
val loginStatus = MutableStateFlow(AuthorizationStatus.CREDENTIALS_LOADING)
|
||||||
private val authManager = AuthorizationManager(application.database.credentialsDao())
|
private val authManager = AuthorizationManager(application.database)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package ru.megboyzz.dnevnik.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import ru.megboyzz.dnevnik.App
|
||||||
|
import ru.megboyzz.dnevnik.entities.context.GroupType
|
||||||
|
import ru.megboyzz.dnevnik.entities.context.SchoolType
|
||||||
|
import ru.megboyzz.dnevnik.entities.db.GlobalUserContext
|
||||||
|
import ru.megboyzz.dnevnik.viewmodel.model.UserProfileModel
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
|
||||||
|
class ProfileViewModel(application: App) : AndroidViewModel(application) {
|
||||||
|
|
||||||
|
val profile = MutableStateFlow<UserProfileModel?>(null)
|
||||||
|
|
||||||
|
val userContextDao = application.database.globalUserContextDao()
|
||||||
|
|
||||||
|
init{
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val globalUserContext = userContextDao.getGlobalUserContext()
|
||||||
|
val convertedProfile = convertGlobalUserContextToProfile(globalUserContext)
|
||||||
|
profile.emit(convertedProfile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertGlobalUserContextToProfile(
|
||||||
|
globalUserContext: GlobalUserContext
|
||||||
|
): UserProfileModel{
|
||||||
|
val info = globalUserContext.apiUserContext.info
|
||||||
|
|
||||||
|
val personContext = globalUserContext.apiUserContext.contextPersons.find {
|
||||||
|
it.school.type == SchoolType.Regular
|
||||||
|
} ?: globalUserContext.apiUserContext.contextPersons[0]
|
||||||
|
|
||||||
|
val term = personContext.reportingPeriodGroup.periods.find {
|
||||||
|
it.isCurrent
|
||||||
|
} ?: personContext.reportingPeriodGroup.periods[0]
|
||||||
|
|
||||||
|
return UserProfileModel(
|
||||||
|
firstName = info.firstName,
|
||||||
|
middleName = info.middleName,
|
||||||
|
lastName = info.lastName,
|
||||||
|
groupName = personContext.group.name,
|
||||||
|
term = term.number + 1,
|
||||||
|
isTerm = term.type == GroupType.Quarter,
|
||||||
|
avatarUrl = info.avatarUrl
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProfileViewModelFactory(private val application: App) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
if (modelClass.isAssignableFrom(ProfileViewModel::class.java))
|
||||||
|
return ProfileViewModel(application) as T
|
||||||
|
throw IllegalArgumentException("Unknown ViewModel Class")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package ru.megboyzz.dnevnik.viewmodel.model
|
||||||
|
|
||||||
|
data class UserProfileModel(
|
||||||
|
val firstName: String,
|
||||||
|
val middleName: String,
|
||||||
|
val lastName: String,
|
||||||
|
val groupName: String,
|
||||||
|
val term: Int,
|
||||||
|
val isTerm: Boolean,
|
||||||
|
val avatarUrl: String
|
||||||
|
){
|
||||||
|
override fun toString() = "$lastName ${firstName.first()}. ${middleName.first()}."
|
||||||
|
}
|
||||||
@@ -72,4 +72,10 @@
|
|||||||
<string name="title_choose_icons">" Select the icons for subjects"</string>
|
<string name="title_choose_icons">" Select the icons for subjects"</string>
|
||||||
<string name="title_enable_notif">Enable notify</string>
|
<string name="title_enable_notif">Enable notify</string>
|
||||||
<string name="title_ok">ОК</string>
|
<string name="title_ok">ОК</string>
|
||||||
|
<string name="tile_leave">Leave</string>
|
||||||
|
<string name="text_leave">Are you sure you want to exit the diary?</string>
|
||||||
|
<string name="title_button_leave">Leave</string>
|
||||||
|
<string name="title_cancel">Cancel</string>
|
||||||
|
<string name="title_quatter_format">Quatter %d</string>
|
||||||
|
<string name="title_sem_format">Semester %d</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -71,4 +71,10 @@
|
|||||||
<string name="title_choose_icons">Выбрать иконки для предметов</string>
|
<string name="title_choose_icons">Выбрать иконки для предметов</string>
|
||||||
<string name="title_enable_notif">Включить уведомления о новых оценках</string>
|
<string name="title_enable_notif">Включить уведомления о новых оценках</string>
|
||||||
<string name="title_ok">Ясно</string>
|
<string name="title_ok">Ясно</string>
|
||||||
|
<string name="tile_leave">Выход</string>
|
||||||
|
<string name="text_leave">Вы точно хотите выйти из дневника? Авторизационные данные будут удалены.</string>
|
||||||
|
<string name="title_button_leave">Выйти</string>
|
||||||
|
<string name="title_cancel">Отмена</string>
|
||||||
|
<string name="title_quatter_format">Идет %d-я четверть</string>
|
||||||
|
<string name="title_sem_format">Идет %d-ий семестр</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user