mirror of
https://github.com/n08i40k/polytechnic-android.git
synced 2025-12-06 09:47:48 +03:00
1.3.0
Верии ниже этой больше не совместимы (т.е не работают). Уменьшение размера приложения. - Существенное) Адекватное кеширование. - Улучшено кеширование на стороне сервера (до этого сервер не выставлял флаг отвечающий за потребность в обновлении). - Добавлено кеширование ответов от сервера в хранилище приложения.
This commit is contained in:
9
.idea/appInsightsSettings.xml
generated
9
.idea/appInsightsSettings.xml
generated
@@ -17,15 +17,6 @@
|
||||
</option>
|
||||
<option name="signal" value="SIGNAL_UNSPECIFIED" />
|
||||
<option name="timeIntervalDays" value="THIRTY_DAYS" />
|
||||
<option name="versions">
|
||||
<list>
|
||||
<VersionSetting>
|
||||
<option name="buildVersion" value="2" />
|
||||
<option name="displayName" value="1.1 (2)" />
|
||||
<option name="displayVersion" value="1.1" />
|
||||
</VersionSetting>
|
||||
</list>
|
||||
</option>
|
||||
<option name="visibilityType" value="ALL" />
|
||||
</InsightsFilterSettings>
|
||||
</value>
|
||||
|
||||
@@ -32,8 +32,8 @@ android {
|
||||
applicationId = "ru.n08i40k.polytechnic.next"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 5
|
||||
versionName = "1.2.2"
|
||||
versionCode = 6
|
||||
versionName = "1.3.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
@@ -43,7 +43,7 @@ android {
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
isMinifyEnabled = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
|
||||
4
app/proguard-rules.pro
vendored
4
app/proguard-rules.pro
vendored
@@ -14,8 +14,8 @@
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
-renamesourcefileattribute SourceFile
|
||||
@@ -6,6 +6,9 @@ import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import ru.n08i40k.polytechnic.next.data.cache.NetworkCacheRepository
|
||||
import ru.n08i40k.polytechnic.next.data.cache.impl.FakeNetworkCacheRepository
|
||||
import ru.n08i40k.polytechnic.next.data.cache.impl.LocalNetworkCacheRepository
|
||||
import ru.n08i40k.polytechnic.next.data.schedule.ScheduleRepository
|
||||
import ru.n08i40k.polytechnic.next.data.schedule.impl.FakeScheduleRepository
|
||||
import ru.n08i40k.polytechnic.next.data.schedule.impl.RemoteScheduleRepository
|
||||
@@ -15,16 +18,24 @@ import ru.n08i40k.polytechnic.next.data.users.impl.RemoteProfileRepository
|
||||
import javax.inject.Singleton
|
||||
|
||||
interface AppContainer {
|
||||
val applicationContext: Context
|
||||
val networkCacheRepository: NetworkCacheRepository
|
||||
val scheduleRepository: ScheduleRepository
|
||||
val profileRepository: ProfileRepository
|
||||
}
|
||||
|
||||
class MockAppContainer : AppContainer {
|
||||
class MockAppContainer(override val applicationContext: Context) : AppContainer {
|
||||
override val networkCacheRepository: NetworkCacheRepository by lazy { FakeNetworkCacheRepository() }
|
||||
override val scheduleRepository: ScheduleRepository by lazy { FakeScheduleRepository() }
|
||||
override val profileRepository: ProfileRepository by lazy { FakeProfileRepository() }
|
||||
}
|
||||
|
||||
class RemoteAppContainer(private val applicationContext: Context) : AppContainer {
|
||||
class RemoteAppContainer(override val applicationContext: Context) : AppContainer {
|
||||
override val networkCacheRepository: NetworkCacheRepository by lazy {
|
||||
LocalNetworkCacheRepository(
|
||||
applicationContext
|
||||
)
|
||||
}
|
||||
override val scheduleRepository: ScheduleRepository by lazy {
|
||||
RemoteScheduleRepository(
|
||||
applicationContext
|
||||
|
||||
15
app/src/main/java/ru/n08i40k/polytechnic/next/data/cache/NetworkCacheRepository.kt
vendored
Normal file
15
app/src/main/java/ru/n08i40k/polytechnic/next/data/cache/NetworkCacheRepository.kt
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package ru.n08i40k.polytechnic.next.data.cache
|
||||
|
||||
import ru.n08i40k.polytechnic.next.CachedResponse
|
||||
|
||||
interface NetworkCacheRepository {
|
||||
suspend fun put(url: String, data: String)
|
||||
|
||||
suspend fun get(url: String): CachedResponse?
|
||||
|
||||
suspend fun clear()
|
||||
|
||||
suspend fun isHashPresent(): Boolean
|
||||
|
||||
suspend fun setHash(hash: String)
|
||||
}
|
||||
20
app/src/main/java/ru/n08i40k/polytechnic/next/data/cache/impl/FakeNetworkCacheRepository.kt
vendored
Normal file
20
app/src/main/java/ru/n08i40k/polytechnic/next/data/cache/impl/FakeNetworkCacheRepository.kt
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package ru.n08i40k.polytechnic.next.data.cache.impl
|
||||
|
||||
import ru.n08i40k.polytechnic.next.CachedResponse
|
||||
import ru.n08i40k.polytechnic.next.data.cache.NetworkCacheRepository
|
||||
|
||||
class FakeNetworkCacheRepository : NetworkCacheRepository {
|
||||
override suspend fun get(url: String): CachedResponse? {
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun put(url: String, data: String) {}
|
||||
|
||||
override suspend fun clear() {}
|
||||
|
||||
override suspend fun isHashPresent(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun setHash(hash: String) {}
|
||||
}
|
||||
93
app/src/main/java/ru/n08i40k/polytechnic/next/data/cache/impl/LocalNetworkCacheRepository.kt
vendored
Normal file
93
app/src/main/java/ru/n08i40k/polytechnic/next/data/cache/impl/LocalNetworkCacheRepository.kt
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
package ru.n08i40k.polytechnic.next.data.cache.impl
|
||||
|
||||
import android.content.Context
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import ru.n08i40k.polytechnic.next.CachedResponse
|
||||
import ru.n08i40k.polytechnic.next.data.cache.NetworkCacheRepository
|
||||
import ru.n08i40k.polytechnic.next.settings.settingsDataStore
|
||||
import javax.inject.Inject
|
||||
|
||||
class LocalNetworkCacheRepository
|
||||
@Inject constructor(private val applicationContext: Context) : NetworkCacheRepository {
|
||||
private val cacheMap: MutableMap<String, CachedResponse> = mutableMapOf()
|
||||
private var hash: String? = null
|
||||
|
||||
init {
|
||||
cacheMap.clear()
|
||||
|
||||
runBlocking {
|
||||
cacheMap.putAll(
|
||||
applicationContext
|
||||
.settingsDataStore
|
||||
.data
|
||||
.map { settings -> settings.cacheStorageMap }.first()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun get(url: String): CachedResponse? {
|
||||
if (this.hash == null)
|
||||
return null
|
||||
|
||||
val response = cacheMap[url]
|
||||
|
||||
if (response?.hash != this.hash)
|
||||
return null
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
override suspend fun put(url: String, data: String) {
|
||||
if (hash == null)
|
||||
throw IllegalStateException("Не установлен хеш!")
|
||||
|
||||
cacheMap[url] = CachedResponse
|
||||
.newBuilder()
|
||||
.setHash(this.hash)
|
||||
.setData(data)
|
||||
.build()
|
||||
|
||||
save()
|
||||
}
|
||||
|
||||
override suspend fun clear() {
|
||||
this.cacheMap.clear()
|
||||
this.save()
|
||||
}
|
||||
|
||||
override suspend fun isHashPresent(): Boolean {
|
||||
return this.hash != null
|
||||
}
|
||||
|
||||
override suspend fun setHash(hash: String) {
|
||||
val freshHash = this.hash == null
|
||||
|
||||
if (!freshHash && this.hash != hash)
|
||||
clear()
|
||||
|
||||
this.hash = hash
|
||||
|
||||
if (freshHash) {
|
||||
this.cacheMap
|
||||
.mapNotNull { if (it.value.hash != this.hash) it.key else null }
|
||||
.forEach { this.cacheMap.remove(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun save() {
|
||||
withContext(Dispatchers.IO) {
|
||||
runBlocking {
|
||||
applicationContext.settingsDataStore.updateData {
|
||||
it
|
||||
.toBuilder()
|
||||
.putAllCacheStorage(cacheMap)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
package ru.n08i40k.polytechnic.next.data.schedule.impl
|
||||
|
||||
import android.content.Context
|
||||
import com.android.volley.Request
|
||||
import com.android.volley.ServerError
|
||||
import com.android.volley.toolbox.RequestFuture
|
||||
import com.android.volley.toolbox.StringRequest
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -13,67 +10,16 @@ import kotlinx.coroutines.withContext
|
||||
import ru.n08i40k.polytechnic.next.data.MyResult
|
||||
import ru.n08i40k.polytechnic.next.data.schedule.ScheduleRepository
|
||||
import ru.n08i40k.polytechnic.next.model.Group
|
||||
import ru.n08i40k.polytechnic.next.network.NetworkConnection
|
||||
import ru.n08i40k.polytechnic.next.network.data.schedule.ScheduleGetRequest
|
||||
import ru.n08i40k.polytechnic.next.network.data.schedule.ScheduleGetRequestData
|
||||
import ru.n08i40k.polytechnic.next.network.data.schedule.ScheduleGetResponse
|
||||
import ru.n08i40k.polytechnic.next.network.data.schedule.ScheduleUpdateRequest
|
||||
import ru.n08i40k.polytechnic.next.network.data.schedule.ScheduleUpdateRequestData
|
||||
import ru.n08i40k.polytechnic.next.settings.settingsDataStore
|
||||
import java.util.logging.Logger
|
||||
import kotlin.io.encoding.Base64
|
||||
import kotlin.io.encoding.ExperimentalEncodingApi
|
||||
|
||||
class RemoteScheduleRepository(private val context: Context) : ScheduleRepository {
|
||||
@OptIn(ExperimentalEncodingApi::class)
|
||||
suspend fun getMainPage(): MyResult<String> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val mainPageFuture = RequestFuture.newFuture<String>()
|
||||
val request = StringRequest(
|
||||
Request.Method.GET,
|
||||
"https://politehnikum-eng.ru/index/raspisanie_zanjatij/0-409",
|
||||
mainPageFuture,
|
||||
mainPageFuture
|
||||
)
|
||||
NetworkConnection.getInstance(context).addToRequestQueue(request)
|
||||
|
||||
try {
|
||||
val encodedMainPage =
|
||||
Base64.Default.encode(mainPageFuture.get().encodeToByteArray())
|
||||
MyResult.Success(encodedMainPage)
|
||||
} catch (exception: Exception) {
|
||||
MyResult.Failure(exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateMainPage(): MyResult<Nothing> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val mainPage = getMainPage()
|
||||
|
||||
if (mainPage is MyResult.Failure)
|
||||
return@withContext mainPage
|
||||
|
||||
val updateFuture = RequestFuture.newFuture<Nothing>()
|
||||
ScheduleUpdateRequest(
|
||||
ScheduleUpdateRequestData((mainPage as MyResult.Success<String>).data),
|
||||
context,
|
||||
updateFuture,
|
||||
updateFuture
|
||||
).send()
|
||||
|
||||
try {
|
||||
MyResult.Success(updateFuture.get())
|
||||
} catch (exception: Exception) {
|
||||
MyResult.Failure(exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getGroup(): MyResult<Group> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val logger = Logger.getLogger("RemoteScheduleRepository")
|
||||
|
||||
val groupName = runBlocking {
|
||||
context.settingsDataStore.data.map { settings -> settings.group }.first()
|
||||
}
|
||||
@@ -81,49 +27,16 @@ class RemoteScheduleRepository(private val context: Context) : ScheduleRepositor
|
||||
if (groupName.isEmpty())
|
||||
return@withContext MyResult.Failure(IllegalArgumentException("No group name provided!"))
|
||||
|
||||
val firstPassFuture = RequestFuture.newFuture<ScheduleGetResponse>()
|
||||
val future = RequestFuture.newFuture<ScheduleGetResponse>()
|
||||
ScheduleGetRequest(
|
||||
ScheduleGetRequestData(groupName),
|
||||
context,
|
||||
firstPassFuture,
|
||||
firstPassFuture
|
||||
).send()
|
||||
|
||||
var firstPassResponse: ScheduleGetResponse? = null
|
||||
|
||||
try {
|
||||
firstPassResponse = firstPassFuture.get()
|
||||
if (!firstPassResponse.updateRequired) {
|
||||
logger.info("Successfully get group schedule!")
|
||||
return@withContext MyResult.Success(firstPassFuture.get().group)
|
||||
}
|
||||
logger.info("Successfully get group schedule, but it needs to update!")
|
||||
} catch (exception: Exception) {
|
||||
if (exception.cause !is ServerError)
|
||||
return@withContext MyResult.Failure(exception)
|
||||
logger.info("Can't get group schedule, because it needs to first update!")
|
||||
}
|
||||
|
||||
val updateResult = updateMainPage()
|
||||
if (updateResult is MyResult.Failure) {
|
||||
logger.info("Can't update site main page!")
|
||||
if (firstPassResponse != null)
|
||||
return@withContext MyResult.Success(firstPassResponse.group)
|
||||
|
||||
return@withContext updateResult
|
||||
}
|
||||
logger.info("Site main page successfully updated!")
|
||||
|
||||
val secondPassFuture = RequestFuture.newFuture<ScheduleGetResponse>()
|
||||
ScheduleGetRequest(
|
||||
ScheduleGetRequestData(groupName),
|
||||
context,
|
||||
secondPassFuture,
|
||||
secondPassFuture
|
||||
future,
|
||||
future
|
||||
).send()
|
||||
|
||||
try {
|
||||
MyResult.Success(secondPassFuture.get().group)
|
||||
MyResult.Success(future.get().group)
|
||||
} catch (exception: Exception) {
|
||||
MyResult.Failure(exception)
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ open class RequestBase(
|
||||
listener: Response.Listener<String>,
|
||||
errorListener: Response.ErrorListener?
|
||||
) : StringRequest(method, NetworkValues.API_HOST + url, listener, errorListener) {
|
||||
fun send() {
|
||||
open fun send() {
|
||||
Logger.getLogger("RequestBase").info("Sending request to $url")
|
||||
NetworkConnection.getInstance(context).addToRequestQueue(this)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import ru.n08i40k.polytechnic.next.ui.model.profileViewModel
|
||||
open class AuthorizedRequest(
|
||||
context: Context,
|
||||
method: Int,
|
||||
url: String?,
|
||||
url: String,
|
||||
listener: Response.Listener<String>,
|
||||
errorListener: Response.ErrorListener?,
|
||||
private val canBeUnauthorized: Boolean = false
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package ru.n08i40k.polytechnic.next.network.data
|
||||
|
||||
import android.content.Context
|
||||
import com.android.volley.Response
|
||||
import com.android.volley.VolleyError
|
||||
import com.android.volley.toolbox.RequestFuture
|
||||
import com.android.volley.toolbox.StringRequest
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import ru.n08i40k.polytechnic.next.PolytechnicApplication
|
||||
import ru.n08i40k.polytechnic.next.data.AppContainer
|
||||
import ru.n08i40k.polytechnic.next.data.MyResult
|
||||
import ru.n08i40k.polytechnic.next.network.NetworkConnection
|
||||
import ru.n08i40k.polytechnic.next.network.data.schedule.ScheduleGetCacheStatusRequest
|
||||
import ru.n08i40k.polytechnic.next.network.data.schedule.ScheduleGetCacheStatusResponse
|
||||
import ru.n08i40k.polytechnic.next.network.data.schedule.ScheduleUpdateRequest
|
||||
import ru.n08i40k.polytechnic.next.network.data.schedule.ScheduleUpdateRequestData
|
||||
import java.util.logging.Logger
|
||||
import kotlin.io.encoding.Base64
|
||||
import kotlin.io.encoding.ExperimentalEncodingApi
|
||||
|
||||
open class CachedRequest(
|
||||
context: Context,
|
||||
method: Int,
|
||||
private val url: String,
|
||||
private val listener: Response.Listener<String>,
|
||||
errorListener: Response.ErrorListener?,
|
||||
) : AuthorizedRequest(context, method, url, {
|
||||
runBlocking {
|
||||
(context as PolytechnicApplication)
|
||||
.container.networkCacheRepository.put(url, it)
|
||||
}
|
||||
listener.onResponse(it)
|
||||
}, errorListener) {
|
||||
private val appContainer: AppContainer = (context as PolytechnicApplication).container
|
||||
|
||||
@OptIn(ExperimentalEncodingApi::class)
|
||||
suspend fun getMainPage(): MyResult<String> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val mainPageFuture = RequestFuture.newFuture<String>()
|
||||
val request = StringRequest(
|
||||
Method.GET,
|
||||
"https://politehnikum-eng.ru/index/raspisanie_zanjatij/0-409",
|
||||
mainPageFuture,
|
||||
mainPageFuture
|
||||
)
|
||||
NetworkConnection.getInstance(context).addToRequestQueue(request)
|
||||
|
||||
try {
|
||||
val encodedMainPage =
|
||||
Base64.Default.encode(mainPageFuture.get().encodeToByteArray())
|
||||
MyResult.Success(encodedMainPage)
|
||||
} catch (exception: Exception) {
|
||||
MyResult.Failure(exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateMainPage(): MyResult<ScheduleGetCacheStatusResponse> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val mainPage = getMainPage()
|
||||
|
||||
if (mainPage is MyResult.Failure)
|
||||
return@withContext mainPage
|
||||
|
||||
val updateFuture = RequestFuture.newFuture<ScheduleGetCacheStatusResponse>()
|
||||
ScheduleUpdateRequest(
|
||||
ScheduleUpdateRequestData((mainPage as MyResult.Success<String>).data),
|
||||
context,
|
||||
updateFuture,
|
||||
updateFuture
|
||||
).send()
|
||||
|
||||
try {
|
||||
MyResult.Success(updateFuture.get())
|
||||
} catch (exception: Exception) {
|
||||
MyResult.Failure(exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun send() {
|
||||
val logger = Logger.getLogger("CachedRequest")
|
||||
|
||||
val repository = appContainer.networkCacheRepository
|
||||
|
||||
val future = RequestFuture.newFuture<ScheduleGetCacheStatusResponse>()
|
||||
|
||||
logger.info("Getting cache status...")
|
||||
ScheduleGetCacheStatusRequest(context, future, future).send()
|
||||
|
||||
try {
|
||||
val response = future.get()
|
||||
|
||||
logger.info("Cache status received successfully!")
|
||||
|
||||
if (!response.cacheUpdateRequired) {
|
||||
logger.info("Cache update was not required!")
|
||||
runBlocking { repository.setHash(response.cacheHash) }
|
||||
} else {
|
||||
logger.info("Cache update was required!")
|
||||
val updateResult = runBlocking { updateMainPage() }
|
||||
|
||||
when (updateResult) {
|
||||
is MyResult.Success -> {
|
||||
logger.info("Cache update was successful!")
|
||||
runBlocking { repository.setHash(updateResult.data.cacheHash) }
|
||||
}
|
||||
|
||||
is MyResult.Failure -> {
|
||||
logger.warning("Failed to update cache!")
|
||||
super.getErrorListener()
|
||||
?.onErrorResponse(updateResult.exception.cause as VolleyError)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
logger.warning("Failed to get cache status!")
|
||||
super.getErrorListener()?.onErrorResponse(exception.cause as VolleyError)
|
||||
return
|
||||
}
|
||||
|
||||
val cachedResponse = runBlocking { repository.get(url) }
|
||||
if (cachedResponse != null) {
|
||||
logger.info("Found cached response!")
|
||||
listener.onResponse(cachedResponse.data)
|
||||
return
|
||||
}
|
||||
|
||||
logger.info("Cached response doesn't exists!")
|
||||
super.send()
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,14 @@ import android.content.Context
|
||||
import com.android.volley.Response
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import ru.n08i40k.polytechnic.next.network.data.AuthorizedRequest
|
||||
import ru.n08i40k.polytechnic.next.network.data.CachedRequest
|
||||
|
||||
class ScheduleGetRequest(
|
||||
private val data: ScheduleGetRequestData,
|
||||
context: Context,
|
||||
listener: Response.Listener<ScheduleGetResponse>,
|
||||
errorListener: Response.ErrorListener? = null
|
||||
) : AuthorizedRequest(
|
||||
) : CachedRequest(
|
||||
context, Method.POST, "schedule/get-group", Response.Listener<String> { response ->
|
||||
listener.onResponse(Json.decodeFromString<ScheduleGetResponse>(response))
|
||||
}, errorListener
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package ru.n08i40k.polytechnic.next.network.data.schedule
|
||||
|
||||
import android.content.Context
|
||||
import com.android.volley.Response
|
||||
import kotlinx.serialization.json.Json
|
||||
import ru.n08i40k.polytechnic.next.network.data.AuthorizedRequest
|
||||
|
||||
class ScheduleGetCacheStatusRequest(
|
||||
context: Context,
|
||||
listener: Response.Listener<ScheduleGetCacheStatusResponse>,
|
||||
errorListener: Response.ErrorListener? = null
|
||||
) : AuthorizedRequest(
|
||||
context, Method.GET, "schedule/cache-status", Response.Listener<String> { response ->
|
||||
listener.onResponse(Json.decodeFromString<ScheduleGetCacheStatusResponse>(response))
|
||||
}, errorListener
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package ru.n08i40k.polytechnic.next.network.data.schedule
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ScheduleGetCacheStatusResponse(
|
||||
val cacheUpdateRequired: Boolean,
|
||||
val cacheHash: String,
|
||||
)
|
||||
@@ -3,13 +3,13 @@ package ru.n08i40k.polytechnic.next.network.data.schedule
|
||||
import android.content.Context
|
||||
import com.android.volley.Response
|
||||
import kotlinx.serialization.json.Json
|
||||
import ru.n08i40k.polytechnic.next.network.data.AuthorizedRequest
|
||||
import ru.n08i40k.polytechnic.next.network.data.CachedRequest
|
||||
|
||||
class ScheduleGetGroupNamesRequest(
|
||||
context: Context,
|
||||
listener: Response.Listener<ScheduleGetGroupNamesResponseData>,
|
||||
errorListener: Response.ErrorListener? = null
|
||||
) : AuthorizedRequest(
|
||||
) : CachedRequest(
|
||||
context, Method.GET, "schedule/get-group-names", Response.Listener<String> { response ->
|
||||
listener.onResponse(Json.decodeFromString<ScheduleGetGroupNamesResponseData>(response))
|
||||
}, errorListener
|
||||
|
||||
@@ -7,7 +7,5 @@ import ru.n08i40k.polytechnic.next.model.Group
|
||||
data class ScheduleGetResponse(
|
||||
val updatedAt: String,
|
||||
val group: Group,
|
||||
val etag: String,
|
||||
val lastChangedDays: ArrayList<Int>,
|
||||
val updateRequired: Boolean
|
||||
)
|
||||
@@ -9,11 +9,11 @@ import ru.n08i40k.polytechnic.next.network.data.AuthorizedRequest
|
||||
class ScheduleUpdateRequest(
|
||||
private val data: ScheduleUpdateRequestData,
|
||||
context: Context,
|
||||
listener: Response.Listener<Nothing>,
|
||||
listener: Response.Listener<ScheduleGetCacheStatusResponse>,
|
||||
errorListener: Response.ErrorListener? = null
|
||||
) : AuthorizedRequest(
|
||||
context, Method.POST, "schedule/update-site-main-page", Response.Listener<String> {
|
||||
listener.onResponse(null)
|
||||
listener.onResponse(Json.decodeFromString<ScheduleGetCacheStatusResponse>(it))
|
||||
}, errorListener
|
||||
) {
|
||||
override fun getBody(): ByteArray {
|
||||
|
||||
@@ -7,6 +7,7 @@ import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
@@ -21,7 +22,7 @@ import ru.n08i40k.polytechnic.next.ui.model.ProfileViewModel
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun ProfileScreen(
|
||||
profileViewModel: ProfileViewModel = ProfileViewModel(MockAppContainer().profileRepository) {},
|
||||
profileViewModel: ProfileViewModel = ProfileViewModel(MockAppContainer(LocalContext.current).profileRepository) {},
|
||||
onRefreshProfile: () -> Unit = {}
|
||||
) {
|
||||
val uiState by profileViewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
@@ -19,7 +20,7 @@ import ru.n08i40k.polytechnic.next.ui.model.ScheduleViewModel
|
||||
@Preview(showBackground = true, showSystemUi = true)
|
||||
@Composable
|
||||
fun ScheduleScreen(
|
||||
scheduleViewModel: ScheduleViewModel = ScheduleViewModel(MockAppContainer()),
|
||||
scheduleViewModel: ScheduleViewModel = ScheduleViewModel(MockAppContainer(LocalContext.current)),
|
||||
onRefreshSchedule: () -> Unit = {}
|
||||
) {
|
||||
val uiState by scheduleViewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
@@ -3,8 +3,14 @@ syntax = "proto3";
|
||||
option java_package = "ru.n08i40k.polytechnic.next";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message CachedResponse {
|
||||
string hash = 1;
|
||||
string data = 2;
|
||||
}
|
||||
|
||||
message Settings {
|
||||
string user_id = 1;
|
||||
string access_token = 2;
|
||||
string group = 3;
|
||||
map<string, CachedResponse> cache_storage = 4;
|
||||
}
|
||||
@@ -2,15 +2,15 @@
|
||||
accompanistSwiperefresh = "0.36.0"
|
||||
agp = "8.6.1"
|
||||
firebaseBom = "33.3.0"
|
||||
hiltAndroid = "2.51.1"
|
||||
hiltAndroidCompiler = "2.51.1"
|
||||
hiltAndroid = "2.52"
|
||||
hiltAndroidCompiler = "2.52"
|
||||
hiltNavigationCompose = "1.2.0"
|
||||
kotlin = "2.0.10"
|
||||
coreKtx = "1.13.1"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.2.1"
|
||||
espressoCore = "3.6.1"
|
||||
kotlinxSerializationJson = "1.7.2"
|
||||
kotlinxSerializationJson = "1.7.3"
|
||||
lifecycleRuntimeKtx = "2.8.6"
|
||||
activityCompose = "1.9.2"
|
||||
composeBom = "2024.09.02"
|
||||
|
||||
Reference in New Issue
Block a user