diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0f943ec..fd43b1a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,7 +5,7 @@ plugins { alias(libs.plugins.androidApplication) alias(libs.plugins.jetbrainsKotlinAndroid) id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") - + id("com.google.devtools.ksp") } secrets { @@ -110,4 +110,8 @@ dependencies { implementation(libs.kefirbb) implementation(libs.acra.http) + + implementation(libs.androidx.room.runtime) + implementation(libs.androidx.room.ktx) + ksp(libs.androidx.room.compiler) } \ No newline at end of file diff --git a/app/src/main/java/ru/sweetbread/unn/API.kt b/app/src/main/java/ru/sweetbread/unn/API.kt index a8ec84e..7e1edc4 100644 --- a/app/src/main/java/ru/sweetbread/unn/API.kt +++ b/app/src/main/java/ru/sweetbread/unn/API.kt @@ -1,13 +1,18 @@ package ru.sweetbread.unn +import android.util.Log import io.ktor.client.request.forms.submitForm import io.ktor.client.request.get import io.ktor.client.request.header import io.ktor.client.request.parameter import io.ktor.client.statement.bodyAsText import io.ktor.http.parameters +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.json.JSONArray import org.json.JSONObject +import ru.sweetbread.unn.db.cacheUser +import ru.sweetbread.unn.db.loadUserByBitrixId import ru.sweetbread.unn.ui.layout.LoginData import ru.sweetbread.unn.ui.layout.client import java.time.LocalDate @@ -28,7 +33,8 @@ enum class Type(val s: String) { Student("student"), Group("group"), Lecturer("lecturer"), - Auditorium("auditorium") + Auditorium("auditorium"), + Employee("employee") } enum class LecturerRank(val id: Int) { @@ -94,7 +100,7 @@ class User( val nameEn: String, val isMale: Boolean, val birthday: LocalDate, - val avatar: ImageSet + val avatar: AvatarSet ) class Post( @@ -107,7 +113,7 @@ class Post( val content: String ) -class ImageSet( +class AvatarSet( val original: String, val thumbnail: String, val small: String @@ -177,7 +183,7 @@ private suspend fun getMyself(login: String) { DateTimeFormatter.ofPattern("yyyy-MM-dd") ), avatar = user.getJSONObject("photo").let { - ImageSet( + AvatarSet( it.getString("orig"), it.getString("thumbnail"), it.getString("small"), @@ -304,10 +310,22 @@ suspend fun getBlogposts(): ArrayList { } suspend fun getUserByBitrixId(id: Int): User { + var user: User? + withContext(Dispatchers.IO) { + user = loadUserByBitrixId(id) + } + user?.let { return user as User } + val userId = JSONObject(client.get("$vuzapiURL/user/bx/$id") { header("Cookie", "PHPSESSID=$PHPSESSID") }.bodyAsText()).getInt("id") - return getUser(userId) + + getUser(userId).let { user -> + withContext(Dispatchers.IO) { + cacheUser(user) + } + return user + } } suspend fun getUser(id: Int): User { @@ -317,14 +335,15 @@ suspend fun getUser(id: Int): User { }.bodyAsText() ) + Log.d("type", json.getJSONArray("profiles").getJSONObject(0).getString("type")) + return User( unnId = null, bitrixId = json.getInt("bitrix_id"), userId = json.getInt("id"), - type = when (json.getJSONArray("profiles").getJSONObject(0).getString("type")) { - "lecturer" -> Type.Lecturer // ig,,, - else -> Type.Student - }, + type = if (json.getJSONArray("profiles").getJSONObject(0) + .getString("type") == "employee" + ) Type.Employee else Type.Student, email = json.getString("email"), nameRu = json.getString("fullname"), nameEn = json.getString("fullname_en"), @@ -334,7 +353,7 @@ suspend fun getUser(id: Int): User { DateTimeFormatter.ofPattern("yyyy-MM-dd") ), avatar = json.getJSONObject("photo").let { - ImageSet( + AvatarSet( it.getString("orig"), it.getString("thumbnail"), it.getString("small"), diff --git a/app/src/main/java/ru/sweetbread/unn/db/DB.kt b/app/src/main/java/ru/sweetbread/unn/db/DB.kt new file mode 100644 index 0000000..2dbdbf7 --- /dev/null +++ b/app/src/main/java/ru/sweetbread/unn/db/DB.kt @@ -0,0 +1,9 @@ +package ru.sweetbread.unn.db + +import androidx.room.Database +import androidx.room.RoomDatabase + +@Database(entities = [UserDB::class], version = 1) +abstract class AppDatabase : RoomDatabase() { + abstract fun userDao(): UserDao +} diff --git a/app/src/main/java/ru/sweetbread/unn/db/UserDB.kt b/app/src/main/java/ru/sweetbread/unn/db/UserDB.kt new file mode 100644 index 0000000..ed05347 --- /dev/null +++ b/app/src/main/java/ru/sweetbread/unn/db/UserDB.kt @@ -0,0 +1,101 @@ +package ru.sweetbread.unn.db + +import android.util.Log +import androidx.room.ColumnInfo +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Entity +import androidx.room.Insert +import androidx.room.PrimaryKey +import androidx.room.Query +import ru.sweetbread.unn.AvatarSet +import ru.sweetbread.unn.Type +import ru.sweetbread.unn.User +import ru.sweetbread.unn.ui.layout.db +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + +@Entity +data class UserDB( + @PrimaryKey val userId: Int, + @ColumnInfo val unnId: Int?, + @ColumnInfo val bitrixId: Int, + @ColumnInfo val type: Type, + @ColumnInfo val email: String, + @ColumnInfo val nameRu: String, + @ColumnInfo val nameEn: String, + @ColumnInfo val isMale: Boolean, + @ColumnInfo val birthday: String, + @ColumnInfo val origAvatar: String, + @ColumnInfo val thumbAvatar: String, + @ColumnInfo val smallAvatar: String, + @ColumnInfo val expiredAt: String +) + +@Dao +interface UserDao { + @Query("SELECT * FROM userDB WHERE bitrixId = :bitrixId LIMIT 1") + fun getUserByBitrix(bitrixId: Int): UserDB? + + @Insert + fun insert(user: UserDB) + + @Delete + fun delete(user: UserDB) +} + + +fun cacheUser(user: User) { + try { + db.userDao().insert( + UserDB( + user.userId, + user.unnId, + user.bitrixId, + user.type, + user.email, + user.nameRu, + user.nameEn, + user.isMale, + user.birthday.format(DateTimeFormatter.ISO_LOCAL_DATE), + user.avatar.original, + user.avatar.thumbnail, + user.avatar.small, + LocalDateTime.now().plusDays(1).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + ) + ) + } catch (_: android.database.sqlite.SQLiteConstraintException) { + } +} + +fun loadUserByBitrixId(bitrixId: Int): User? { + val user = db.userDao().getUserByBitrix(bitrixId) + Log.d("UserDB", user?.nameEn ?: "None") + if (user == null) return null + if (LocalDateTime.parse( + user.expiredAt, + DateTimeFormatter.ISO_LOCAL_DATE_TIME + ) < LocalDateTime.now() + ) { + db.userDao().delete(user) + return null + } else { + return User( + user.unnId, + user.bitrixId, + user.userId, + user.type, + user.email, + user.nameRu, + user.nameEn, + user.isMale, + LocalDate.parse(user.birthday, DateTimeFormatter.ISO_LOCAL_DATE), + AvatarSet( + user.origAvatar, + user.thumbAvatar, + user.smallAvatar + ) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/sweetbread/unn/ui/composes/Blogpost.kt b/app/src/main/java/ru/sweetbread/unn/ui/composes/Blogpost.kt index d8222fc..e24fc19 100644 --- a/app/src/main/java/ru/sweetbread/unn/ui/composes/Blogpost.kt +++ b/app/src/main/java/ru/sweetbread/unn/ui/composes/Blogpost.kt @@ -48,7 +48,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import org.kefirsf.bb.BBProcessorFactory import org.kefirsf.bb.TextProcessor -import ru.sweetbread.unn.ImageSet +import ru.sweetbread.unn.AvatarSet import ru.sweetbread.unn.Post import ru.sweetbread.unn.R import ru.sweetbread.unn.Type @@ -73,7 +73,7 @@ val defUser = User( "Jon Sigma Omega", true, LocalDate.now(), - ImageSet( + AvatarSet( "https://upload.wikimedia.org/wikipedia/ru/thumb/9/94/%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg/500px-%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg", "https://upload.wikimedia.org/wikipedia/ru/thumb/9/94/%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg/500px-%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg", "https://upload.wikimedia.org/wikipedia/ru/thumb/9/94/%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg/500px-%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg" diff --git a/app/src/main/java/ru/sweetbread/unn/ui/layout/MainActivity.kt b/app/src/main/java/ru/sweetbread/unn/ui/layout/MainActivity.kt index 1f2e1c5..57178bc 100644 --- a/app/src/main/java/ru/sweetbread/unn/ui/layout/MainActivity.kt +++ b/app/src/main/java/ru/sweetbread/unn/ui/layout/MainActivity.kt @@ -25,6 +25,7 @@ import androidx.compose.ui.Modifier import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import androidx.room.Room import io.ktor.client.HttpClient import io.ktor.client.plugins.HttpRequestRetry import io.ktor.client.plugins.HttpTimeout @@ -32,6 +33,7 @@ import io.ktor.client.plugins.cache.HttpCache import io.ktor.client.plugins.logging.LogLevel import io.ktor.client.plugins.logging.Logger import io.ktor.client.plugins.logging.Logging +import ru.sweetbread.unn.db.AppDatabase import ru.sweetbread.unn.ui.composes.Blogposts import ru.sweetbread.unn.ui.composes.Schedule import ru.sweetbread.unn.ui.theme.UNNTheme @@ -59,10 +61,18 @@ val client = HttpClient { } } +lateinit var db: AppDatabase + class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + db = Room.databaseBuilder( + applicationContext, + AppDatabase::class.java, "database" + ).build() + setContent { UNNTheme { Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { diff --git a/build.gradle.kts b/build.gradle.kts index 1e1eb7c..d565c5a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,7 @@ plugins { alias(libs.plugins.androidApplication) apply false alias(libs.plugins.jetbrainsKotlinAndroid) apply false + id("com.google.devtools.ksp") version "1.9.0-1.0.13" apply false } buildscript { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1e71df7..4d4a3e4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,6 +24,7 @@ lifecycleLivedataKtx = "2.7.0" lifecycleViewmodelKtx = "2.7.0" activity = "1.8.2" navigationCompose = "2.7.7" +roomRuntime = "2.6.1" secretsGradlePlugin = "2.0.1" splittiesFunPackAndroidBaseWithViewsDsl = "3.0.0" kefirbb = "1.5" @@ -34,6 +35,9 @@ androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" } androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" } androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" } +androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomRuntime" } +androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "roomRuntime" } +androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomRuntime" } coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coilCompose" } compose = { module = "com.kizitonwose.calendar:compose", version.ref = "compose" } desugar_jdk_libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar_jdk_libs" }