mirror of
https://github.com/n08i40k/polytechnic-android.git
synced 2025-12-06 09:47:48 +03:00
3.1.1
Кешированные ответы от сервера теперь находятся в специальном файле, а не в настройках. Возвращён просмотр подробностей о паре.
This commit is contained in:
6
.idea/kotlinc.xml
generated
6
.idea/kotlinc.xml
generated
@@ -7,10 +7,10 @@
|
|||||||
<option name="jvmTarget" value="1.8" />
|
<option name="jvmTarget" value="1.8" />
|
||||||
</component>
|
</component>
|
||||||
<component name="KotlinCommonCompilerArguments">
|
<component name="KotlinCommonCompilerArguments">
|
||||||
<option name="apiVersion" value="2.0" />
|
<option name="apiVersion" value="2.1" />
|
||||||
<option name="languageVersion" value="2.0" />
|
<option name="languageVersion" value="2.1" />
|
||||||
</component>
|
</component>
|
||||||
<component name="KotlinJpsPluginSettings">
|
<component name="KotlinJpsPluginSettings">
|
||||||
<option name="version" value="2.0.10" />
|
<option name="version" value="2.1.10" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -46,8 +46,8 @@ android {
|
|||||||
applicationId = "ru.n08i40k.polytechnic.next"
|
applicationId = "ru.n08i40k.polytechnic.next"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 27
|
versionCode = 28
|
||||||
versionName = "3.1.0"
|
versionName = "3.1.1"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@ dependencies {
|
|||||||
|
|
||||||
protobuf {
|
protobuf {
|
||||||
protoc {
|
protoc {
|
||||||
artifact = "com.google.protobuf:protoc:4.29.3"
|
artifact = "com.google.protobuf:protoc:21.0-rc-1"
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ import kotlinx.coroutines.flow.first
|
|||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import ru.n08i40k.polytechnic.next.app.AppContainer
|
import ru.n08i40k.polytechnic.next.app.AppContainer
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
|
import ru.n08i40k.polytechnic.next.proto.settings_v0
|
||||||
import ru.n08i40k.polytechnic.next.utils.Observable
|
import ru.n08i40k.polytechnic.next.utils.Observable
|
||||||
import ru.n08i40k.polytechnic.next.worker.UpdateFCMTokenWorker
|
import ru.n08i40k.polytechnic.next.worker.UpdateFCMTokenWorker
|
||||||
import ru.n08i40k.polytechnic.next.worker.UpdateLinkWorker
|
import ru.n08i40k.polytechnic.next.worker.UpdateLinkWorker
|
||||||
@@ -97,8 +98,35 @@ class Application : Application() {
|
|||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
|
runBlocking { fixupSettings() }
|
||||||
|
|
||||||
VKID.init(this)
|
VKID.init(this)
|
||||||
|
|
||||||
setupFirebase()
|
setupFirebase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun fixupSettings() {
|
||||||
|
val accessToken = this.settings_v0.data.map { it.accessToken }.first()
|
||||||
|
|
||||||
|
if (accessToken.isEmpty())
|
||||||
|
return
|
||||||
|
|
||||||
|
val userId = this.settings_v0.data.map { it.userId }.first()
|
||||||
|
val group = this.settings_v0.data.map { it.group }.first()
|
||||||
|
val version = this.settings_v0.data.map { it.version }.first()
|
||||||
|
val fcmToken = this.settings_v0.data.map { it.fcmToken }.first()
|
||||||
|
|
||||||
|
this.settings.updateData {
|
||||||
|
it
|
||||||
|
.toBuilder()
|
||||||
|
.setUserId(userId)
|
||||||
|
.setAccessToken(accessToken)
|
||||||
|
.setGroup(group)
|
||||||
|
.setVersion(version)
|
||||||
|
.setFcmToken(fcmToken)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.settings_v0.updateData { it.toBuilder().clear().build() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.n08i40k.polytechnic.next.app.NotificationChannels
|
import ru.n08i40k.polytechnic.next.app.NotificationChannels
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
import ru.n08i40k.polytechnic.next.ui.PolytechnicApp
|
import ru.n08i40k.polytechnic.next.ui.PolytechnicApp
|
||||||
import ru.n08i40k.polytechnic.next.ui.theme.AppTheme
|
import ru.n08i40k.polytechnic.next.ui.theme.AppTheme
|
||||||
import ru.n08i40k.polytechnic.next.utils.app
|
import ru.n08i40k.polytechnic.next.utils.app
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.os.Parcelable
|
|||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import ru.n08i40k.polytechnic.next.R
|
import ru.n08i40k.polytechnic.next.R
|
||||||
|
import ru.n08i40k.polytechnic.next.utils.dayMinutes
|
||||||
import ru.n08i40k.polytechnic.next.utils.limit
|
import ru.n08i40k.polytechnic.next.utils.limit
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@@ -17,6 +18,8 @@ data class Lesson(
|
|||||||
val group: String? = null,
|
val group: String? = null,
|
||||||
val subGroups: List<SubGroup>
|
val subGroups: List<SubGroup>
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
val duration: Int get() = time.end.dayMinutes - time.start.dayMinutes
|
||||||
|
|
||||||
fun getShortName(context: Context): String {
|
fun getShortName(context: Context): String {
|
||||||
val name =
|
val name =
|
||||||
if (type == LessonType.BREAK)
|
if (type == LessonType.BREAK)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import ru.n08i40k.polytechnic.next.app.AppContainer
|
import ru.n08i40k.polytechnic.next.app.AppContainer
|
||||||
import ru.n08i40k.polytechnic.next.network.RequestBase
|
import ru.n08i40k.polytechnic.next.network.RequestBase
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
|
|
||||||
open class AuthorizedRequest(
|
open class AuthorizedRequest(
|
||||||
val appContainer: AppContainer,
|
val appContainer: AppContainer,
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package ru.n08i40k.polytechnic.next.proto
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.datastore.core.CorruptionException
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.core.Serializer
|
||||||
|
import androidx.datastore.dataStore
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException
|
||||||
|
import ru.n08i40k.polytechnic.next.Cache
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
object CacheSerializer : Serializer<Cache> {
|
||||||
|
override val defaultValue: Cache = Cache.getDefaultInstance()
|
||||||
|
|
||||||
|
override suspend fun readFrom(input: InputStream): Cache =
|
||||||
|
try {
|
||||||
|
Cache.parseFrom(input)
|
||||||
|
} catch (exception: InvalidProtocolBufferException) {
|
||||||
|
throw CorruptionException("Cannot read proto.", exception)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun writeTo(t: Cache, output: OutputStream) = t.writeTo(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
val Context.cache: DataStore<Cache> by dataStore(
|
||||||
|
fileName = "cache.pb",
|
||||||
|
serializer = CacheSerializer
|
||||||
|
)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package ru.n08i40k.polytechnic.next.settings
|
package ru.n08i40k.polytechnic.next.proto
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.datastore.core.CorruptionException
|
import androidx.datastore.core.CorruptionException
|
||||||
@@ -23,7 +23,7 @@ object SettingsSerializer : Serializer<Settings> {
|
|||||||
override suspend fun writeTo(t: Settings, output: OutputStream) = t.writeTo(output)
|
override suspend fun writeTo(t: Settings, output: OutputStream) = t.writeTo(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
val Context.settings: DataStore<Settings> by dataStore(
|
val Context.settings_v0: DataStore<Settings> by dataStore(
|
||||||
fileName = "settings.pb",
|
fileName = "settings.pb",
|
||||||
serializer = SettingsSerializer
|
serializer = SettingsSerializer
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package ru.n08i40k.polytechnic.next.proto
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.datastore.core.CorruptionException
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.core.Serializer
|
||||||
|
import androidx.datastore.dataStore
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException
|
||||||
|
import ru.n08i40k.polytechnic.next.SettingsV2
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
object SettingsV2Serializer : Serializer<SettingsV2> {
|
||||||
|
override val defaultValue: SettingsV2 = SettingsV2.getDefaultInstance()
|
||||||
|
|
||||||
|
override suspend fun readFrom(input: InputStream): SettingsV2 =
|
||||||
|
try {
|
||||||
|
SettingsV2.parseFrom(input)
|
||||||
|
} catch (exception: InvalidProtocolBufferException) {
|
||||||
|
throw CorruptionException("Cannot read proto.", exception)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun writeTo(t: SettingsV2, output: OutputStream) = t.writeTo(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
val Context.settings: DataStore<SettingsV2> by dataStore(
|
||||||
|
fileName = "settings-v2.pb",
|
||||||
|
serializer = SettingsV2Serializer
|
||||||
|
)
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package ru.n08i40k.polytechnic.next.repository.cache
|
package ru.n08i40k.polytechnic.next.repository.cache
|
||||||
|
|
||||||
import ru.n08i40k.polytechnic.next.CachedResponse
|
import ru.n08i40k.polytechnic.next.CacheDate
|
||||||
import ru.n08i40k.polytechnic.next.UpdateDates
|
import ru.n08i40k.polytechnic.next.CacheResponse
|
||||||
|
|
||||||
interface NetworkCacheRepository {
|
interface NetworkCacheRepository {
|
||||||
suspend fun put(url: String, data: String)
|
suspend fun put(url: String, data: String)
|
||||||
|
|
||||||
suspend fun get(url: String): CachedResponse?
|
suspend fun get(url: String): CacheResponse?
|
||||||
|
|
||||||
suspend fun clear()
|
suspend fun clear()
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ interface NetworkCacheRepository {
|
|||||||
|
|
||||||
suspend fun setHash(hash: String)
|
suspend fun setHash(hash: String)
|
||||||
|
|
||||||
suspend fun getUpdateDates(): UpdateDates
|
suspend fun getUpdateDates(): CacheDate
|
||||||
|
|
||||||
suspend fun setUpdateDates(cache: Long, schedule: Long)
|
suspend fun setUpdateDates(cache: Long, schedule: Long)
|
||||||
}
|
}
|
||||||
@@ -5,17 +5,18 @@ import kotlinx.coroutines.flow.first
|
|||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import ru.n08i40k.polytechnic.next.CachedResponse
|
import ru.n08i40k.polytechnic.next.CacheDate
|
||||||
import ru.n08i40k.polytechnic.next.UpdateDates
|
import ru.n08i40k.polytechnic.next.CacheResponse
|
||||||
import ru.n08i40k.polytechnic.next.app.AppContainer
|
import ru.n08i40k.polytechnic.next.app.AppContainer
|
||||||
|
import ru.n08i40k.polytechnic.next.proto.cache
|
||||||
import ru.n08i40k.polytechnic.next.repository.cache.NetworkCacheRepository
|
import ru.n08i40k.polytechnic.next.repository.cache.NetworkCacheRepository
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LocalNetworkCacheRepository
|
class LocalNetworkCacheRepository
|
||||||
@Inject constructor(private val appContainer: AppContainer) : NetworkCacheRepository {
|
@Inject constructor(private val appContainer: AppContainer) : NetworkCacheRepository {
|
||||||
private val cacheMap: MutableMap<String, CachedResponse> = mutableMapOf()
|
private val cacheMap: MutableMap<String, CacheResponse> = mutableMapOf()
|
||||||
private var updateDates: UpdateDates = UpdateDates.newBuilder().build()
|
private var cacheDate: CacheDate = CacheDate.newBuilder().build()
|
||||||
|
|
||||||
private var hash: String? = null
|
private var hash: String? = null
|
||||||
|
|
||||||
private val context get() = appContainer.context
|
private val context get() = appContainer.context
|
||||||
@@ -26,14 +27,14 @@ class LocalNetworkCacheRepository
|
|||||||
runBlocking {
|
runBlocking {
|
||||||
cacheMap.putAll(
|
cacheMap.putAll(
|
||||||
context
|
context
|
||||||
.settings
|
.cache
|
||||||
.data
|
.data
|
||||||
.map { settings -> settings.cacheStorageMap }.first()
|
.map { it.storageMap }.first()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun get(url: String): CachedResponse? {
|
override suspend fun get(url: String): CacheResponse? {
|
||||||
// Если кешированного ответа нет, то возвращаем null
|
// Если кешированного ответа нет, то возвращаем null
|
||||||
// Если хеши не совпадают и локальный хеш присутствует, то возвращаем null
|
// Если хеши не совпадают и локальный хеш присутствует, то возвращаем null
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ class LocalNetworkCacheRepository
|
|||||||
if (hash == null)
|
if (hash == null)
|
||||||
throw IllegalStateException("Не установлен хеш!")
|
throw IllegalStateException("Не установлен хеш!")
|
||||||
|
|
||||||
cacheMap[url] = CachedResponse
|
cacheMap[url] = CacheResponse
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setHash(this.hash)
|
.setHash(this.hash)
|
||||||
.setData(data)
|
.setData(data)
|
||||||
@@ -83,21 +84,21 @@ class LocalNetworkCacheRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getUpdateDates(): UpdateDates {
|
override suspend fun getUpdateDates(): CacheDate {
|
||||||
return this.updateDates
|
return this.cacheDate
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setUpdateDates(cache: Long, schedule: Long) {
|
override suspend fun setUpdateDates(cache: Long, schedule: Long) {
|
||||||
updateDates = UpdateDates
|
cacheDate = CacheDate
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.setCache(cache)
|
.setCache(cache)
|
||||||
.setSchedule(schedule).build()
|
.setSchedule(schedule).build()
|
||||||
|
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
context.settings.updateData {
|
context.cache.updateData {
|
||||||
it
|
it
|
||||||
.toBuilder()
|
.toBuilder()
|
||||||
.setUpdateDates(updateDates)
|
.setDate(cacheDate)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,10 +107,10 @@ class LocalNetworkCacheRepository
|
|||||||
|
|
||||||
private suspend fun save() {
|
private suspend fun save() {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
context.settings.updateData {
|
context.cache.updateData {
|
||||||
it
|
it
|
||||||
.toBuilder()
|
.toBuilder()
|
||||||
.putAllCacheStorage(cacheMap)
|
.putAllStorage(cacheMap)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package ru.n08i40k.polytechnic.next.repository.cache.impl
|
package ru.n08i40k.polytechnic.next.repository.cache.impl
|
||||||
|
|
||||||
import ru.n08i40k.polytechnic.next.CachedResponse
|
import ru.n08i40k.polytechnic.next.CacheDate
|
||||||
import ru.n08i40k.polytechnic.next.UpdateDates
|
import ru.n08i40k.polytechnic.next.CacheResponse
|
||||||
import ru.n08i40k.polytechnic.next.repository.cache.NetworkCacheRepository
|
import ru.n08i40k.polytechnic.next.repository.cache.NetworkCacheRepository
|
||||||
|
|
||||||
class MockNetworkCacheRepository : NetworkCacheRepository {
|
class MockNetworkCacheRepository : NetworkCacheRepository {
|
||||||
override suspend fun get(url: String): CachedResponse? {
|
override suspend fun get(url: String): CacheResponse? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,8 +19,8 @@ class MockNetworkCacheRepository : NetworkCacheRepository {
|
|||||||
|
|
||||||
override suspend fun setHash(hash: String) {}
|
override suspend fun setHash(hash: String) {}
|
||||||
|
|
||||||
override suspend fun getUpdateDates(): UpdateDates {
|
override suspend fun getUpdateDates(): CacheDate {
|
||||||
return UpdateDates.newBuilder().build()
|
return CacheDate.newBuilder().build()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setUpdateDates(cache: Long, schedule: Long) {}
|
override suspend fun setUpdateDates(cache: Long, schedule: Long) {}
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import ru.n08i40k.polytechnic.next.model.Profile
|
|||||||
import ru.n08i40k.polytechnic.next.network.request.fcm.FcmSetToken
|
import ru.n08i40k.polytechnic.next.network.request.fcm.FcmSetToken
|
||||||
import ru.n08i40k.polytechnic.next.network.request.profile.ProfileMe
|
import ru.n08i40k.polytechnic.next.network.request.profile.ProfileMe
|
||||||
import ru.n08i40k.polytechnic.next.network.tryFuture
|
import ru.n08i40k.polytechnic.next.network.tryFuture
|
||||||
|
import ru.n08i40k.polytechnic.next.proto.cache
|
||||||
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
import ru.n08i40k.polytechnic.next.repository.profile.ProfileRepository
|
import ru.n08i40k.polytechnic.next.repository.profile.ProfileRepository
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
|
||||||
import ru.n08i40k.polytechnic.next.utils.MyResult
|
import ru.n08i40k.polytechnic.next.utils.MyResult
|
||||||
import ru.n08i40k.polytechnic.next.utils.app
|
import ru.n08i40k.polytechnic.next.utils.app
|
||||||
|
|
||||||
@@ -40,7 +41,14 @@ class RemoteProfileRepository(private val container: AppContainer) : ProfileRepo
|
|||||||
override suspend fun signOut() {
|
override suspend fun signOut() {
|
||||||
val context = container.context
|
val context = container.context
|
||||||
|
|
||||||
container.context.settings.updateData {
|
context.settings.updateData {
|
||||||
|
it
|
||||||
|
.toBuilder()
|
||||||
|
.clear()
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
context.cache.updateData {
|
||||||
it
|
it
|
||||||
.toBuilder()
|
.toBuilder()
|
||||||
.clear()
|
.clear()
|
||||||
@@ -48,12 +56,5 @@ class RemoteProfileRepository(private val container: AppContainer) : ProfileRepo
|
|||||||
}
|
}
|
||||||
|
|
||||||
context.app.events.signOut.next(Unit)
|
context.app.events.signOut.next(Unit)
|
||||||
|
|
||||||
// context.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)
|
|
||||||
// val pm = context.packageManager
|
|
||||||
// val intent = pm.getLaunchIntentForPackage(context.packageName)
|
|
||||||
// val mainIntent = Intent.makeRestartActivityTask(intent?.component)
|
|
||||||
// context.startActivity(mainIntent)
|
|
||||||
// Runtime.getRuntime().exit(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import ru.n08i40k.polytechnic.next.Application
|
import ru.n08i40k.polytechnic.next.Application
|
||||||
import ru.n08i40k.polytechnic.next.R
|
import ru.n08i40k.polytechnic.next.R
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
import ru.n08i40k.polytechnic.next.ui.screen.MainScreen
|
import ru.n08i40k.polytechnic.next.ui.screen.MainScreen
|
||||||
import ru.n08i40k.polytechnic.next.ui.screen.auth.AuthScreen
|
import ru.n08i40k.polytechnic.next.ui.screen.auth.AuthScreen
|
||||||
import ru.n08i40k.polytechnic.next.utils.app
|
import ru.n08i40k.polytechnic.next.utils.app
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.n08i40k.polytechnic.next.UpdateDates
|
import ru.n08i40k.polytechnic.next.CacheDate
|
||||||
import ru.n08i40k.polytechnic.next.app.AppContainer
|
import ru.n08i40k.polytechnic.next.app.AppContainer
|
||||||
import ru.n08i40k.polytechnic.next.model.GroupOrTeacher
|
import ru.n08i40k.polytechnic.next.model.GroupOrTeacher
|
||||||
import ru.n08i40k.polytechnic.next.utils.MyResult
|
import ru.n08i40k.polytechnic.next.utils.MyResult
|
||||||
@@ -25,7 +25,7 @@ sealed interface GroupUiState {
|
|||||||
|
|
||||||
data class HasData(
|
data class HasData(
|
||||||
val group: GroupOrTeacher,
|
val group: GroupOrTeacher,
|
||||||
val updateDates: UpdateDates,
|
val cacheDate: CacheDate,
|
||||||
val lastUpdateAt: Long,
|
val lastUpdateAt: Long,
|
||||||
override val isLoading: Boolean
|
override val isLoading: Boolean
|
||||||
) : GroupUiState
|
) : GroupUiState
|
||||||
@@ -33,7 +33,7 @@ sealed interface GroupUiState {
|
|||||||
|
|
||||||
private data class GroupViewModelState(
|
private data class GroupViewModelState(
|
||||||
val group: GroupOrTeacher? = null,
|
val group: GroupOrTeacher? = null,
|
||||||
val updateDates: UpdateDates? = null,
|
val updateDates: CacheDate? = null,
|
||||||
val lastUpdateAt: Long = 0,
|
val lastUpdateAt: Long = 0,
|
||||||
val isLoading: Boolean = false
|
val isLoading: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.n08i40k.polytechnic.next.UpdateDates
|
import ru.n08i40k.polytechnic.next.CacheDate
|
||||||
import ru.n08i40k.polytechnic.next.app.AppContainer
|
import ru.n08i40k.polytechnic.next.app.AppContainer
|
||||||
import ru.n08i40k.polytechnic.next.model.GroupOrTeacher
|
import ru.n08i40k.polytechnic.next.model.GroupOrTeacher
|
||||||
import ru.n08i40k.polytechnic.next.utils.MyResult
|
import ru.n08i40k.polytechnic.next.utils.MyResult
|
||||||
@@ -25,7 +25,7 @@ sealed interface SearchUiState {
|
|||||||
|
|
||||||
data class HasData(
|
data class HasData(
|
||||||
val teacher: GroupOrTeacher,
|
val teacher: GroupOrTeacher,
|
||||||
val updateDates: UpdateDates,
|
val cacheDate: CacheDate,
|
||||||
val lastUpdateAt: Long,
|
val lastUpdateAt: Long,
|
||||||
override val isLoading: Boolean
|
override val isLoading: Boolean
|
||||||
) : SearchUiState
|
) : SearchUiState
|
||||||
@@ -33,7 +33,7 @@ sealed interface SearchUiState {
|
|||||||
|
|
||||||
private data class SearchViewModelState(
|
private data class SearchViewModelState(
|
||||||
val teacher: GroupOrTeacher? = null,
|
val teacher: GroupOrTeacher? = null,
|
||||||
val updateDates: UpdateDates? = null,
|
val updateDates: CacheDate? = null,
|
||||||
val lastUpdateAt: Long = 0,
|
val lastUpdateAt: Long = 0,
|
||||||
val isLoading: Boolean = false
|
val isLoading: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.n08i40k.polytechnic.next.UpdateDates
|
import ru.n08i40k.polytechnic.next.CacheDate
|
||||||
import ru.n08i40k.polytechnic.next.app.AppContainer
|
import ru.n08i40k.polytechnic.next.app.AppContainer
|
||||||
import ru.n08i40k.polytechnic.next.model.GroupOrTeacher
|
import ru.n08i40k.polytechnic.next.model.GroupOrTeacher
|
||||||
import ru.n08i40k.polytechnic.next.utils.MyResult
|
import ru.n08i40k.polytechnic.next.utils.MyResult
|
||||||
@@ -24,7 +24,7 @@ sealed interface TeacherUiState {
|
|||||||
|
|
||||||
data class HasData(
|
data class HasData(
|
||||||
val teacher: GroupOrTeacher,
|
val teacher: GroupOrTeacher,
|
||||||
val updateDates: UpdateDates,
|
val cacheDate: CacheDate,
|
||||||
val lastUpdateAt: Long,
|
val lastUpdateAt: Long,
|
||||||
override val isLoading: Boolean
|
override val isLoading: Boolean
|
||||||
) : TeacherUiState
|
) : TeacherUiState
|
||||||
@@ -32,7 +32,7 @@ sealed interface TeacherUiState {
|
|||||||
|
|
||||||
private data class TeacherViewModelState(
|
private data class TeacherViewModelState(
|
||||||
val teacher: GroupOrTeacher? = null,
|
val teacher: GroupOrTeacher? = null,
|
||||||
val updateDates: UpdateDates? = null,
|
val updateDates: CacheDate? = null,
|
||||||
val lastUpdateAt: Long = 0,
|
val lastUpdateAt: Long = 0,
|
||||||
val isLoading: Boolean = false
|
val isLoading: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import kotlinx.coroutines.runBlocking
|
|||||||
import ru.n08i40k.polytechnic.next.Application
|
import ru.n08i40k.polytechnic.next.Application
|
||||||
import ru.n08i40k.polytechnic.next.R
|
import ru.n08i40k.polytechnic.next.R
|
||||||
import ru.n08i40k.polytechnic.next.model.UserRole
|
import ru.n08i40k.polytechnic.next.model.UserRole
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
import ru.n08i40k.polytechnic.next.ui.AppRoute
|
import ru.n08i40k.polytechnic.next.ui.AppRoute
|
||||||
import ru.n08i40k.polytechnic.next.ui.icons.AppIcons
|
import ru.n08i40k.polytechnic.next.ui.icons.AppIcons
|
||||||
import ru.n08i40k.polytechnic.next.ui.icons.appicons.Filled
|
import ru.n08i40k.polytechnic.next.ui.icons.appicons.Filled
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ import androidx.navigation.compose.rememberNavController
|
|||||||
import com.google.android.gms.tasks.OnCompleteListener
|
import com.google.android.gms.tasks.OnCompleteListener
|
||||||
import com.google.android.gms.tasks.Task
|
import com.google.android.gms.tasks.Task
|
||||||
import com.google.firebase.messaging.FirebaseMessaging
|
import com.google.firebase.messaging.FirebaseMessaging
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import ru.n08i40k.polytechnic.next.proto.cache
|
||||||
import ru.n08i40k.polytechnic.next.ui.AppRoute
|
import ru.n08i40k.polytechnic.next.ui.AppRoute
|
||||||
import ru.n08i40k.polytechnic.next.ui.helper.PushSnackbar
|
import ru.n08i40k.polytechnic.next.ui.helper.PushSnackbar
|
||||||
import ru.n08i40k.polytechnic.next.ui.helper.SnackbarBox
|
import ru.n08i40k.polytechnic.next.ui.helper.SnackbarBox
|
||||||
@@ -61,8 +63,7 @@ private fun FormWrapper(
|
|||||||
with(localDensity) {
|
with(localDensity) {
|
||||||
onWidthChange(it.size.width.toDp())
|
onWidthChange(it.size.width.toDp())
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
/*.animateContentSize()*/,
|
|
||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -84,6 +85,8 @@ private fun AuthForm(parentNavController: NavController, pushSnackbar: PushSnack
|
|||||||
}
|
}
|
||||||
|
|
||||||
val finish: () -> Unit = {
|
val finish: () -> Unit = {
|
||||||
|
runBlocking { context.cache.updateData { it.toBuilder().clear().build() } }
|
||||||
|
|
||||||
parentNavController.navigate(AppRoute.MAIN.route) {
|
parentNavController.navigate(AppRoute.MAIN.route) {
|
||||||
popUpTo(AppRoute.AUTH.route) { inclusive = true }
|
popUpTo(AppRoute.AUTH.route) { inclusive = true }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import kotlinx.coroutines.runBlocking
|
|||||||
import ru.n08i40k.polytechnic.next.R
|
import ru.n08i40k.polytechnic.next.R
|
||||||
import ru.n08i40k.polytechnic.next.network.request.auth.AuthSignIn
|
import ru.n08i40k.polytechnic.next.network.request.auth.AuthSignIn
|
||||||
import ru.n08i40k.polytechnic.next.network.unwrapException
|
import ru.n08i40k.polytechnic.next.network.unwrapException
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
import ru.n08i40k.polytechnic.next.ui.helper.PushSnackbar
|
import ru.n08i40k.polytechnic.next.ui.helper.PushSnackbar
|
||||||
import ru.n08i40k.polytechnic.next.ui.helper.data.rememberInputValue
|
import ru.n08i40k.polytechnic.next.ui.helper.data.rememberInputValue
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import ru.n08i40k.polytechnic.next.network.request.auth.AuthSignInVK
|
import ru.n08i40k.polytechnic.next.network.request.auth.AuthSignInVK
|
||||||
import ru.n08i40k.polytechnic.next.network.unwrapException
|
import ru.n08i40k.polytechnic.next.network.unwrapException
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
import ru.n08i40k.polytechnic.next.ui.widgets.OneTapComplete
|
import ru.n08i40k.polytechnic.next.ui.widgets.OneTapComplete
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import ru.n08i40k.polytechnic.next.R
|
|||||||
import ru.n08i40k.polytechnic.next.model.UserRole
|
import ru.n08i40k.polytechnic.next.model.UserRole
|
||||||
import ru.n08i40k.polytechnic.next.network.request.auth.AuthSignUp
|
import ru.n08i40k.polytechnic.next.network.request.auth.AuthSignUp
|
||||||
import ru.n08i40k.polytechnic.next.network.unwrapException
|
import ru.n08i40k.polytechnic.next.network.unwrapException
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
import ru.n08i40k.polytechnic.next.ui.helper.PushSnackbar
|
import ru.n08i40k.polytechnic.next.ui.helper.PushSnackbar
|
||||||
import ru.n08i40k.polytechnic.next.ui.helper.data.rememberInputValue
|
import ru.n08i40k.polytechnic.next.ui.helper.data.rememberInputValue
|
||||||
import ru.n08i40k.polytechnic.next.ui.widgets.selector.GroupSelector
|
import ru.n08i40k.polytechnic.next.ui.widgets.selector.GroupSelector
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import ru.n08i40k.polytechnic.next.R
|
|||||||
import ru.n08i40k.polytechnic.next.model.UserRole
|
import ru.n08i40k.polytechnic.next.model.UserRole
|
||||||
import ru.n08i40k.polytechnic.next.network.request.auth.AuthSignUpVK
|
import ru.n08i40k.polytechnic.next.network.request.auth.AuthSignUpVK
|
||||||
import ru.n08i40k.polytechnic.next.network.unwrapException
|
import ru.n08i40k.polytechnic.next.network.unwrapException
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
import ru.n08i40k.polytechnic.next.ui.helper.PushSnackbar
|
import ru.n08i40k.polytechnic.next.ui.helper.PushSnackbar
|
||||||
import ru.n08i40k.polytechnic.next.ui.helper.data.rememberInputValue
|
import ru.n08i40k.polytechnic.next.ui.helper.data.rememberInputValue
|
||||||
import ru.n08i40k.polytechnic.next.ui.widgets.selector.GroupSelector
|
import ru.n08i40k.polytechnic.next.ui.widgets.selector.GroupSelector
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ fun GroupScheduleScreen(viewModel: GroupViewModel) {
|
|||||||
Column {
|
Column {
|
||||||
val data = uiState as GroupUiState.HasData
|
val data = uiState as GroupUiState.HasData
|
||||||
|
|
||||||
UpdateInfo(data.lastUpdateAt, data.updateDates)
|
UpdateInfo(data.lastUpdateAt, data.cacheDate)
|
||||||
Spacer(Modifier.height(10.dp))
|
Spacer(Modifier.height(10.dp))
|
||||||
SchedulePager(data.group)
|
SchedulePager(data.group)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ fun TeacherScheduleScreen(viewModel: TeacherViewModel) {
|
|||||||
Column {
|
Column {
|
||||||
val data = uiState as TeacherUiState.HasData
|
val data = uiState as TeacherUiState.HasData
|
||||||
|
|
||||||
UpdateInfo(data.lastUpdateAt, data.updateDates)
|
UpdateInfo(data.lastUpdateAt, data.cacheDate)
|
||||||
Spacer(Modifier.height(10.dp))
|
Spacer(Modifier.height(10.dp))
|
||||||
SchedulePager(data.teacher)
|
SchedulePager(data.teacher)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ fun TeacherSearchScreen(viewModel: SearchViewModel) {
|
|||||||
Column {
|
Column {
|
||||||
val data = uiState as SearchUiState.HasData
|
val data = uiState as SearchUiState.HasData
|
||||||
|
|
||||||
UpdateInfo(data.lastUpdateAt, data.updateDates)
|
UpdateInfo(data.lastUpdateAt, data.cacheDate)
|
||||||
Spacer(Modifier.height(10.dp))
|
Spacer(Modifier.height(10.dp))
|
||||||
SchedulePager(data.teacher)
|
SchedulePager(data.teacher)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import androidx.compose.ui.text.font.FontFamily
|
|||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ru.n08i40k.polytechnic.next.CacheDate
|
||||||
import ru.n08i40k.polytechnic.next.R
|
import ru.n08i40k.polytechnic.next.R
|
||||||
import ru.n08i40k.polytechnic.next.UpdateDates
|
|
||||||
import ru.n08i40k.polytechnic.next.ui.widgets.ExpandableCard
|
import ru.n08i40k.polytechnic.next.ui.widgets.ExpandableCard
|
||||||
import ru.n08i40k.polytechnic.next.ui.widgets.ExpandableCardTitle
|
import ru.n08i40k.polytechnic.next.ui.widgets.ExpandableCardTitle
|
||||||
import ru.n08i40k.polytechnic.next.utils.*
|
import ru.n08i40k.polytechnic.next.utils.*
|
||||||
@@ -32,15 +32,15 @@ val expanded = mutableStateOf(false)
|
|||||||
@Composable
|
@Composable
|
||||||
fun UpdateInfo(
|
fun UpdateInfo(
|
||||||
lastUpdateAt: Long = 0,
|
lastUpdateAt: Long = 0,
|
||||||
updateDates: UpdateDates = UpdateDates.newBuilder().build()
|
cacheDate: CacheDate = CacheDate.newBuilder().build()
|
||||||
) {
|
) {
|
||||||
var expanded by remember { expanded }
|
var expanded by remember { expanded }
|
||||||
|
|
||||||
val format = "HH:mm:ss dd.MM.yyyy"
|
val format = "HH:mm:ss dd.MM.yyyy"
|
||||||
|
|
||||||
val currentDate = Date(lastUpdateAt).toString(format)
|
val currentDate = Date(lastUpdateAt).toString(format)
|
||||||
val cacheUpdateDate = Date(updateDates.cache).toString(format)
|
val cacheUpdateDate = Date(cacheDate.cache).toString(format)
|
||||||
val scheduleUpdateDate = Date(updateDates.schedule).toString(format)
|
val scheduleUpdateDate = Date(cacheDate.schedule).toString(format)
|
||||||
|
|
||||||
ExpandableCard(
|
ExpandableCard(
|
||||||
expanded = expanded,
|
expanded = expanded,
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@@ -34,6 +32,7 @@ import kotlinx.coroutines.flow.flow
|
|||||||
import kotlinx.datetime.LocalDateTime
|
import kotlinx.datetime.LocalDateTime
|
||||||
import ru.n08i40k.polytechnic.next.R
|
import ru.n08i40k.polytechnic.next.R
|
||||||
import ru.n08i40k.polytechnic.next.model.Day
|
import ru.n08i40k.polytechnic.next.model.Day
|
||||||
|
import ru.n08i40k.polytechnic.next.model.Lesson
|
||||||
import ru.n08i40k.polytechnic.next.model.LessonType
|
import ru.n08i40k.polytechnic.next.model.LessonType
|
||||||
import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository
|
import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository
|
||||||
import ru.n08i40k.polytechnic.next.utils.dateTime
|
import ru.n08i40k.polytechnic.next.utils.dateTime
|
||||||
@@ -80,7 +79,8 @@ private fun getCurrentLessonIdx(day: Day?): Flow<Int> {
|
|||||||
@Composable
|
@Composable
|
||||||
fun DayCard(
|
fun DayCard(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
day: Day = MockScheduleRepository.exampleTeacher.days[0]
|
day: Day = MockScheduleRepository.exampleTeacher.days[0],
|
||||||
|
onLessonClick: (Lesson) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val offset = remember(day) { getDayOffset(day) }
|
val offset = remember(day) { getDayOffset(day) }
|
||||||
|
|
||||||
@@ -119,9 +119,9 @@ fun DayCard(
|
|||||||
style = MaterialTheme.typography.titleLarge
|
style = MaterialTheme.typography.titleLarge
|
||||||
)
|
)
|
||||||
|
|
||||||
if (day.street != null) {
|
day.street?.let {
|
||||||
Text(
|
Text(
|
||||||
day.street,
|
it,
|
||||||
Modifier.fillMaxWidth(),
|
Modifier.fillMaxWidth(),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
)
|
)
|
||||||
@@ -177,12 +177,9 @@ fun DayCard(
|
|||||||
LessonType.EXAM_DEFAULT -> examCardColors
|
LessonType.EXAM_DEFAULT -> examCardColors
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Вернуть ExtraInfo
|
|
||||||
var extraInfo by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.clickable { extraInfo = true }
|
.clickable { onLessonClick(lesson) }
|
||||||
.background(cardColors.containerColor)
|
.background(cardColors.containerColor)
|
||||||
) {
|
) {
|
||||||
val modifier =
|
val modifier =
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package ru.n08i40k.polytechnic.next.ui.widgets.schedule
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.max
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import ru.n08i40k.polytechnic.next.R
|
||||||
|
import ru.n08i40k.polytechnic.next.model.Lesson
|
||||||
|
import ru.n08i40k.polytechnic.next.model.LessonType
|
||||||
|
import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository
|
||||||
|
import ru.n08i40k.polytechnic.next.utils.dayMinutes
|
||||||
|
import ru.n08i40k.polytechnic.next.utils.fmtAsClock
|
||||||
|
|
||||||
|
class LessonPreviewParameterProvider : PreviewParameterProvider<Lesson> {
|
||||||
|
override val values: Sequence<Lesson>
|
||||||
|
get() {
|
||||||
|
val lessons = MockScheduleRepository.exampleGroup.days[0].lessons
|
||||||
|
|
||||||
|
return sequenceOf(
|
||||||
|
lessons[0],
|
||||||
|
lessons[2],
|
||||||
|
lessons[4],
|
||||||
|
lessons[6],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun ExtraInfoDialogPreview(
|
||||||
|
@PreviewParameter(LessonPreviewParameterProvider::class) lesson: Lesson
|
||||||
|
) {
|
||||||
|
ExtraInfoDialog(lesson) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ExtraInfoDialog(
|
||||||
|
lesson: Lesson,
|
||||||
|
onDismiss: () -> Unit
|
||||||
|
) {
|
||||||
|
Dialog(onDismiss) {
|
||||||
|
Card {
|
||||||
|
Column(Modifier.padding(10.dp)) {
|
||||||
|
var minWidth by remember { mutableStateOf(Dp.Unspecified) }
|
||||||
|
val density = LocalDensity.current
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun kvText(title: String, text: String) {
|
||||||
|
Row(
|
||||||
|
Modifier.alpha(if (minWidth == Dp.Unspecified) 0f else 1f),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
Modifier
|
||||||
|
.onGloballyPositioned {
|
||||||
|
with(density) {
|
||||||
|
val dp = it.size.width.toDp()
|
||||||
|
|
||||||
|
minWidth =
|
||||||
|
if (minWidth == Dp.Unspecified)
|
||||||
|
dp
|
||||||
|
else
|
||||||
|
max(minWidth, dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.size(minWidth, Dp.Unspecified),
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
textAlign = TextAlign.Right,
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kvText(stringResource(R.string.extra_info_lesson_name), lesson.name ?: "")
|
||||||
|
when (lesson.type) {
|
||||||
|
LessonType.BREAK -> throw IllegalArgumentException()
|
||||||
|
LessonType.DEFAULT -> null
|
||||||
|
LessonType.ADDITIONAL -> null
|
||||||
|
LessonType.CONSULTATION -> R.string.lesson_type_consultation
|
||||||
|
LessonType.INDEPENDENT_WORK -> R.string.lesson_type_independent_work
|
||||||
|
LessonType.EXAM -> R.string.lesson_type_exam
|
||||||
|
LessonType.EXAM_WITH_GRADE -> R.string.lesson_type_exam_with_grade
|
||||||
|
LessonType.EXAM_DEFAULT -> R.string.lesson_type_exam_default
|
||||||
|
}?.let {
|
||||||
|
kvText(stringResource(R.string.extra_info_type), stringResource(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lesson.subGroups.size == 1) {
|
||||||
|
kvText(
|
||||||
|
stringResource(R.string.extra_info_teacher),
|
||||||
|
stringResource(
|
||||||
|
R.string.extra_info_teacher_second,
|
||||||
|
lesson.subGroups[0].teacher,
|
||||||
|
lesson.subGroups[0].cabinet
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
for (subGroup in lesson.subGroups) {
|
||||||
|
kvText(
|
||||||
|
stringResource(R.string.extra_info_teacher),
|
||||||
|
stringResource(
|
||||||
|
R.string.extra_info_teacher_second_subgroup,
|
||||||
|
subGroup.teacher,
|
||||||
|
subGroup.cabinet,
|
||||||
|
subGroup.number
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kvText(
|
||||||
|
stringResource(R.string.extra_info_duration),
|
||||||
|
stringResource(
|
||||||
|
R.string.extra_info_duration_second,
|
||||||
|
lesson.time.start.dayMinutes.fmtAsClock(),
|
||||||
|
lesson.time.end.dayMinutes.fmtAsClock(),
|
||||||
|
lesson.duration / 60,
|
||||||
|
lesson.duration % 60
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,10 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
@@ -17,10 +21,13 @@ import androidx.compose.ui.util.lerp
|
|||||||
import kotlinx.datetime.LocalDateTime
|
import kotlinx.datetime.LocalDateTime
|
||||||
import ru.n08i40k.polytechnic.next.R
|
import ru.n08i40k.polytechnic.next.R
|
||||||
import ru.n08i40k.polytechnic.next.model.GroupOrTeacher
|
import ru.n08i40k.polytechnic.next.model.GroupOrTeacher
|
||||||
|
import ru.n08i40k.polytechnic.next.model.Lesson
|
||||||
|
import ru.n08i40k.polytechnic.next.model.LessonType
|
||||||
import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository
|
import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository
|
||||||
import ru.n08i40k.polytechnic.next.ui.widgets.NotificationCard
|
import ru.n08i40k.polytechnic.next.ui.widgets.NotificationCard
|
||||||
import ru.n08i40k.polytechnic.next.utils.dateTime
|
import ru.n08i40k.polytechnic.next.utils.dateTime
|
||||||
import ru.n08i40k.polytechnic.next.utils.now
|
import ru.n08i40k.polytechnic.next.utils.now
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
@@ -40,6 +47,8 @@ fun SchedulePager(schedule: GroupOrTeacher = MockScheduleRepository.exampleTeach
|
|||||||
pageCount = { schedule.days.size }
|
pageCount = { schedule.days.size }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var dialogLesson by remember { mutableStateOf<WeakReference<Lesson>?>(null) }
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
if (isScheduleOutdated(schedule))
|
if (isScheduleOutdated(schedule))
|
||||||
NotificationCard(Level.WARNING, stringResource(R.string.outdated_schedule))
|
NotificationCard(Level.WARNING, stringResource(R.string.outdated_schedule))
|
||||||
@@ -69,7 +78,14 @@ fun SchedulePager(schedule: GroupOrTeacher = MockScheduleRepository.exampleTeach
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
schedule.days[page]
|
schedule.days[page]
|
||||||
)
|
) { dialogLesson = WeakReference(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialogLesson?.get()?.let { lesson ->
|
||||||
|
if (lesson.type == LessonType.BREAK)
|
||||||
|
return@let
|
||||||
|
|
||||||
|
ExtraInfoDialog(lesson) { dialogLesson = null }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ import kotlinx.coroutines.flow.first
|
|||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import ru.n08i40k.polytechnic.next.app.appContainer
|
import ru.n08i40k.polytechnic.next.app.appContainer
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
import ru.n08i40k.polytechnic.next.utils.MyResult
|
import ru.n08i40k.polytechnic.next.utils.MyResult
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import androidx.work.WorkerParameters
|
|||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import ru.n08i40k.polytechnic.next.app.appContainer
|
import ru.n08i40k.polytechnic.next.app.appContainer
|
||||||
import ru.n08i40k.polytechnic.next.settings.settings
|
import ru.n08i40k.polytechnic.next.proto.settings
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|
||||||
|
|||||||
19
app/src/main/proto/cache.proto
Normal file
19
app/src/main/proto/cache.proto
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "ru.n08i40k.polytechnic.next";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
message CacheResponse {
|
||||||
|
string hash = 1;
|
||||||
|
string data = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CacheDate {
|
||||||
|
int64 cache = 1;
|
||||||
|
int64 schedule = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Cache {
|
||||||
|
map<string, CacheResponse> storage = 4;
|
||||||
|
CacheDate date = 5;
|
||||||
|
}
|
||||||
15
app/src/main/proto/settings-v2.proto
Normal file
15
app/src/main/proto/settings-v2.proto
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "ru.n08i40k.polytechnic.next";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
message SettingsV2 {
|
||||||
|
string user_id = 1;
|
||||||
|
string access_token = 2;
|
||||||
|
string group = 3;
|
||||||
|
|
||||||
|
string version = 5;
|
||||||
|
string suppressed_version = 6;
|
||||||
|
|
||||||
|
string fcm_token = 7;
|
||||||
|
}
|
||||||
@@ -100,4 +100,11 @@
|
|||||||
<string name="day_view_end_description">Ура, можно идти домой! Наверное :(</string>
|
<string name="day_view_end_description">Ура, можно идти домой! Наверное :(</string>
|
||||||
<string name="day_view_channel_name">Текущая пара</string>
|
<string name="day_view_channel_name">Текущая пара</string>
|
||||||
<string name="day_view_channel_description">Отображает текущую пару или перемену в уведомлении</string>
|
<string name="day_view_channel_description">Отображает текущую пару или перемену в уведомлении</string>
|
||||||
|
<string name="extra_info_lesson_name">"Название: "</string>
|
||||||
|
<string name="extra_info_teacher">"Преподаватель: "</string>
|
||||||
|
<string name="extra_info_teacher_second">%1$s в %2$s каб.</string>
|
||||||
|
<string name="extra_info_teacher_second_subgroup">%1$s в %2$s каб. [подгруппа - %3$d]</string>
|
||||||
|
<string name="extra_info_duration">"Длительность: "</string>
|
||||||
|
<string name="extra_info_duration_second">С %1$s до %2$s (%3$d ч. %4$d мин.)</string>
|
||||||
|
<string name="extra_info_type">"Тип: "</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -100,4 +100,11 @@
|
|||||||
<string name="day_view_end_description">ya ne budu eto perevidit\'</string>
|
<string name="day_view_end_description">ya ne budu eto perevidit\'</string>
|
||||||
<string name="day_view_channel_name">Current lesson</string>
|
<string name="day_view_channel_name">Current lesson</string>
|
||||||
<string name="day_view_channel_description">View the current lesson and breaks in notification</string>
|
<string name="day_view_channel_description">View the current lesson and breaks in notification</string>
|
||||||
|
<string name="extra_info_lesson_name">"Name: "</string>
|
||||||
|
<string name="extra_info_teacher">"Teacher: "</string>
|
||||||
|
<string name="extra_info_teacher_second">%1$s in %2$s cab.</string>
|
||||||
|
<string name="extra_info_teacher_second_subgroup">%1$s in %2$s cab. [subgroup - %3$d]</string>
|
||||||
|
<string name="extra_info_duration">"Duration: "</string>
|
||||||
|
<string name="extra_info_duration_second">From %1$s to %2$s (%3$d h. %4$d min.)</string>
|
||||||
|
<string name="extra_info_type">"Type: "</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,27 +1,28 @@
|
|||||||
[versions]
|
[versions]
|
||||||
agp = "8.8.1"
|
agp = "8.8.2"
|
||||||
desugar_jdk_libs = "2.1.4"
|
desugar_jdk_libs = "2.1.5"
|
||||||
kotlin = "2.1.10"
|
kotlin = "2.1.10"
|
||||||
coreKtx = "1.15.0"
|
coreKtx = "1.15.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.2.1"
|
junitVersion = "1.2.1"
|
||||||
espressoCore = "3.6.1"
|
espressoCore = "3.6.1"
|
||||||
lifecycleRuntimeKtx = "2.8.7"
|
lifecycleRuntimeKtx = "2.8.7"
|
||||||
activityCompose = "1.10.0"
|
activityCompose = "1.10.1"
|
||||||
composeBom = "2025.02.00"
|
composeBom = "2025.03.00"
|
||||||
accompanistSwiperefresh = "0.36.0"
|
accompanistSwiperefresh = "0.36.0"
|
||||||
firebaseBom = "33.9.0"
|
firebaseBom = "33.10.0"
|
||||||
hiltAndroid = "2.55"
|
hiltAndroid = "2.55"
|
||||||
hiltAndroidCompiler = "2.55"
|
hiltAndroidCompiler = "2.55"
|
||||||
hiltNavigationCompose = "1.2.0"
|
hiltNavigationCompose = "1.2.0"
|
||||||
kotlinxSerializationJson = "1.8.0"
|
kotlinxSerializationJson = "1.8.0"
|
||||||
protobufLite = "3.0.1"
|
protobufLite = "3.0.1"
|
||||||
volley = "1.2.1"
|
volley = "1.2.1"
|
||||||
datastore = "1.1.2"
|
datastore = "1.1.3"
|
||||||
navigationCompose = "2.8.9"
|
navigationCompose = "2.8.9"
|
||||||
googleFirebaseCrashlytics = "3.0.3"
|
googleFirebaseCrashlytics = "3.0.3"
|
||||||
workRuntime = "2.10.0"
|
workRuntime = "2.10.0"
|
||||||
vkid = "2.3.1"
|
#noinspection GradleDependency
|
||||||
|
vkid = "2.2.2"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
@@ -59,8 +60,8 @@ volley = { group = "com.android.volley", name = "volley", version.ref = "volley"
|
|||||||
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
|
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
|
||||||
|
|
||||||
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
|
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
|
||||||
firebase-analytics = { module = "com.google.firebase:firebase-analytics", version = "22.2.0" }
|
firebase-analytics = { module = "com.google.firebase:firebase-analytics", version = "22.3.0" }
|
||||||
firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics", version = "19.4.0" }
|
firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics", version = "19.4.1" }
|
||||||
firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging", version = "24.1.0" }
|
firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging", version = "24.1.0" }
|
||||||
firebase-config = { group = "com.google.firebase", name = "firebase-config", version = "22.1.0" }
|
firebase-config = { group = "com.google.firebase", name = "firebase-config", version = "22.1.0" }
|
||||||
vk-vkid = {group = "com.vk.id", name = "vkid", version.ref = "vkid" }
|
vk-vkid = {group = "com.vk.id", name = "vkid", version.ref = "vkid" }
|
||||||
|
|||||||
Reference in New Issue
Block a user