diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml
index bac18c6..f23fb71 100644
--- a/.idea/appInsightsSettings.xml
+++ b/.idea/appInsightsSettings.xml
@@ -20,9 +20,9 @@
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..bce97c3
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..79ee123
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 2904b84..4c85420 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -7,7 +7,7 @@
-
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index ef5c2a0..0b7bda7 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -32,8 +32,8 @@ android {
applicationId = "ru.n08i40k.polytechnic.next"
minSdk = 26
targetSdk = 35
- versionCode = 7
- versionName = "1.3.1"
+ versionCode = 8
+ versionName = "1.3.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/data/MyResult.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/data/MyResult.kt
index 272e3b2..79c83c9 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/data/MyResult.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/data/MyResult.kt
@@ -1,7 +1,5 @@
package ru.n08i40k.polytechnic.next.data
-import java.lang.Exception
-
sealed interface MyResult {
data class Success(val data: T) : MyResult
data class Failure(val exception: Exception) : MyResult
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/data/cache/impl/LocalNetworkCacheRepository.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/data/cache/impl/LocalNetworkCacheRepository.kt
index fe914ab..586282b 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/data/cache/impl/LocalNetworkCacheRepository.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/data/cache/impl/LocalNetworkCacheRepository.kt
@@ -32,12 +32,12 @@ class LocalNetworkCacheRepository
}
override suspend fun get(url: String): CachedResponse? {
- if (this.hash == null)
- return null
+ // Если кешированого ответа нет, то возвращаем null
+ // Если хеши не совпадают и локальный хеш присутствует, то возвращаем null
- val response = cacheMap[url]
+ val response = cacheMap[url] ?: return null
- if (response?.hash != this.hash)
+ if (response.hash != this.hash && this.hash != null)
return null
return response
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/ScheduleRepository.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/ScheduleRepository.kt
index d7198ac..62a952b 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/ScheduleRepository.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/ScheduleRepository.kt
@@ -1,7 +1,7 @@
package ru.n08i40k.polytechnic.next.data.schedule
-import ru.n08i40k.polytechnic.next.model.Group
import ru.n08i40k.polytechnic.next.data.MyResult
+import ru.n08i40k.polytechnic.next.model.Group
interface ScheduleRepository {
suspend fun getGroup(): MyResult
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/impl/FakeScheduleRepository.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/impl/FakeScheduleRepository.kt
index 8e83e35..2f678fc 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/impl/FakeScheduleRepository.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/impl/FakeScheduleRepository.kt
@@ -4,13 +4,13 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
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.Day
import ru.n08i40k.polytechnic.next.model.Group
-import ru.n08i40k.polytechnic.next.data.schedule.ScheduleRepository
import ru.n08i40k.polytechnic.next.model.Lesson
import ru.n08i40k.polytechnic.next.model.LessonTime
import ru.n08i40k.polytechnic.next.model.LessonType
-import ru.n08i40k.polytechnic.next.data.MyResult
class FakeScheduleRepository : ScheduleRepository {
@Suppress("SpellCheckingInspection")
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/impl/RemoteScheduleRepository.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/impl/RemoteScheduleRepository.kt
index 198161c..9d42c3b 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/impl/RemoteScheduleRepository.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/data/schedule/impl/RemoteScheduleRepository.kt
@@ -1,7 +1,6 @@
package ru.n08i40k.polytechnic.next.data.schedule.impl
import android.content.Context
-import com.android.volley.toolbox.RequestFuture
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@@ -12,7 +11,7 @@ import ru.n08i40k.polytechnic.next.data.schedule.ScheduleRepository
import ru.n08i40k.polytechnic.next.model.Group
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.tryFuture
import ru.n08i40k.polytechnic.next.settings.settingsDataStore
class RemoteScheduleRepository(private val context: Context) : ScheduleRepository {
@@ -27,18 +26,18 @@ class RemoteScheduleRepository(private val context: Context) : ScheduleRepositor
if (groupName.isEmpty())
return@withContext MyResult.Failure(IllegalArgumentException("No group name provided!"))
- val future = RequestFuture.newFuture()
- ScheduleGetRequest(
- ScheduleGetRequestData(groupName),
- context,
- future,
- future
- ).send()
+ val response = tryFuture {
+ ScheduleGetRequest(
+ ScheduleGetRequestData(groupName),
+ context,
+ it,
+ it
+ )
+ }
- try {
- MyResult.Success(future.get().group)
- } catch (exception: Exception) {
- MyResult.Failure(exception)
+ when (response) {
+ is MyResult.Failure -> response
+ is MyResult.Success -> MyResult.Success(response.data.group)
}
}
}
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/data/users/impl/FakeProfileRepository.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/data/users/impl/FakeProfileRepository.kt
index fbfe27a..4deeef6 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/data/users/impl/FakeProfileRepository.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/data/users/impl/FakeProfileRepository.kt
@@ -7,7 +7,6 @@ import ru.n08i40k.polytechnic.next.data.MyResult
import ru.n08i40k.polytechnic.next.data.users.ProfileRepository
import ru.n08i40k.polytechnic.next.model.Profile
import ru.n08i40k.polytechnic.next.model.UserRole
-import java.lang.Exception
class FakeProfileRepository : ProfileRepository {
private var counter = 0
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/data/users/impl/RemoteProfileRepository.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/data/users/impl/RemoteProfileRepository.kt
index 3f5eab4..53916ec 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/data/users/impl/RemoteProfileRepository.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/data/users/impl/RemoteProfileRepository.kt
@@ -1,28 +1,23 @@
package ru.n08i40k.polytechnic.next.data.users.impl
import android.content.Context
-import com.android.volley.toolbox.RequestFuture
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import ru.n08i40k.polytechnic.next.data.MyResult
import ru.n08i40k.polytechnic.next.data.users.ProfileRepository
import ru.n08i40k.polytechnic.next.model.Profile
import ru.n08i40k.polytechnic.next.network.data.profile.UsersMeRequest
+import ru.n08i40k.polytechnic.next.network.tryFuture
class RemoteProfileRepository(private val context: Context) : ProfileRepository {
override suspend fun getProfile(): MyResult {
return withContext(Dispatchers.IO) {
- val responseFuture = RequestFuture.newFuture()
- UsersMeRequest(
- context,
- responseFuture,
- responseFuture
- ).send()
-
- try {
- MyResult.Success(responseFuture.get())
- } catch (exception: Exception) {
- MyResult.Failure(exception)
+ tryFuture {
+ UsersMeRequest(
+ context,
+ it,
+ it
+ )
}
}
}
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/network/Request.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/network/Request.kt
index 9d3d96c..f296e89 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/network/Request.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/network/Request.kt
@@ -5,10 +5,15 @@ import android.content.Context
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.Response
+import com.android.volley.VolleyError
import com.android.volley.toolbox.HurlStack
+import com.android.volley.toolbox.RequestFuture
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
+import ru.n08i40k.polytechnic.next.data.MyResult
import java.security.cert.X509Certificate
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.TimeoutException
import java.util.logging.Logger
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
@@ -82,3 +87,23 @@ open class RequestBase(
return headers
}
}
+
+fun tryFuture(
+ buildRequest: (RequestFuture) -> RequestT
+): MyResult {
+ val future = RequestFuture.newFuture()
+ buildRequest(future).send()
+ return tryGet(future)
+}
+
+fun tryGet(future: RequestFuture): MyResult {
+ return try {
+ MyResult.Success(future.get())
+ } catch (exception: VolleyError) {
+ MyResult.Failure(exception)
+ } catch (exception: ExecutionException) {
+ MyResult.Failure(exception.cause as VolleyError)
+ } catch (exception: TimeoutException) {
+ MyResult.Failure(exception)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/network/data/CachedRequest.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/network/data/CachedRequest.kt
index a383eff..0012fc6 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/network/data/CachedRequest.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/network/data/CachedRequest.kt
@@ -2,7 +2,6 @@ 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
@@ -16,6 +15,8 @@ import ru.n08i40k.polytechnic.next.network.data.schedule.ScheduleGetCacheStatusR
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 ru.n08i40k.polytechnic.next.network.tryFuture
+import ru.n08i40k.polytechnic.next.network.tryGet
import java.util.logging.Logger
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
@@ -47,61 +48,58 @@ open class CachedRequest(
)
NetworkConnection.getInstance(context).addToRequestQueue(request)
- try {
- val encodedMainPage =
- Base64.Default.encode(mainPageFuture.get().encodeToByteArray())
- MyResult.Success(encodedMainPage)
- } catch (exception: Exception) {
- MyResult.Failure(exception)
+ when (val response = tryGet(mainPageFuture)) {
+ is MyResult.Failure -> response
+ is MyResult.Success -> {
+ val encodedMainPage = Base64.Default.encode(response.data.encodeToByteArray())
+ MyResult.Success(encodedMainPage)
+ }
}
}
}
private suspend fun updateMainPage(): MyResult {
return withContext(Dispatchers.IO) {
- val mainPage = getMainPage()
-
- if (mainPage is MyResult.Failure)
- return@withContext mainPage
-
- val updateFuture = RequestFuture.newFuture()
- ScheduleUpdateRequest(
- ScheduleUpdateRequestData((mainPage as MyResult.Success).data),
- context,
- updateFuture,
- updateFuture
- ).send()
-
- try {
- MyResult.Success(updateFuture.get())
- } catch (exception: Exception) {
- MyResult.Failure(exception)
+ when (val mainPage = getMainPage()) {
+ is MyResult.Failure -> mainPage
+ is MyResult.Success -> {
+ tryFuture {
+ ScheduleUpdateRequest(
+ ScheduleUpdateRequestData(mainPage.data),
+ context,
+ it,
+ it
+ )
+ }
+ }
}
}
}
override fun send() {
val logger = Logger.getLogger("CachedRequest")
-
val repository = appContainer.networkCacheRepository
- val future = RequestFuture.newFuture()
-
logger.info("Getting cache status...")
- ScheduleGetCacheStatusRequest(context, future, future).send()
- try {
- val response = future.get()
+ val cacheStatusResult = tryFuture {
+ ScheduleGetCacheStatusRequest(context, it, it)
+ }
+
+ if (cacheStatusResult is MyResult.Success) {
+ val cacheStatus = cacheStatusResult.data
logger.info("Cache status received successfully!")
- if (!response.cacheUpdateRequired) {
- logger.info("Cache update was not required!")
- runBlocking {
- repository.setUpdateDates(response.lastCacheUpdate, response.lastScheduleUpdate)
- repository.setHash(response.cacheHash)
- }
- } else {
+ runBlocking {
+ repository.setUpdateDates(
+ cacheStatus.lastCacheUpdate,
+ cacheStatus.lastScheduleUpdate
+ )
+ repository.setHash(cacheStatus.cacheHash)
+ }
+
+ if (cacheStatus.cacheUpdateRequired) {
logger.info("Cache update was required!")
val updateResult = runBlocking { updateMainPage() }
@@ -119,16 +117,11 @@ open class CachedRequest(
is MyResult.Failure -> {
logger.warning("Failed to update cache!")
- super.getErrorListener()
- ?.onErrorResponse(updateResult.exception.cause as VolleyError)
- return
}
}
}
- } catch (exception: Exception) {
+ } else {
logger.warning("Failed to get cache status!")
- super.getErrorListener()?.onErrorResponse(exception.cause as VolleyError)
- return
}
val cachedResponse = runBlocking { repository.get(url) }
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/ExpandableCard.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/ExpandableCard.kt
index 3e97948..5e30cd4 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/ExpandableCard.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/ExpandableCard.kt
@@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material3.Card
+import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -27,6 +28,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@@ -46,10 +48,13 @@ fun ExpandableCard(
val transition = rememberTransition(transitionState)
- Card(modifier = modifier.clickable {
- onExpandedChange()
- transitionState.targetState = expanded
- }) {
+ Card(
+ modifier = modifier.clickable {
+ onExpandedChange()
+ transitionState.targetState = expanded
+ },
+ shape = RectangleShape
+ ) {
Column {
ExpandableCardHeader(title, transition)
ExpandableCardContent(visible = expanded, content = content)
@@ -83,6 +88,7 @@ private fun ExpandableCardContent(
enter = enterTransition,
exit = exitTransition
) {
+ HorizontalDivider()
content()
}
}
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/profile/ProfileCard.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/profile/ProfileCard.kt
index 021aca8..2b7a557 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/profile/ProfileCard.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/profile/ProfileCard.kt
@@ -149,7 +149,7 @@ internal fun ProfileCard(profile: Profile = FakeProfileRepository.exampleProfile
.build()
}
}
-
+
context.profileViewModel!!.onUnauthorized()
}) {
Text(stringResource(R.string.sign_out))
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt
index 836d4f8..d1a41a3 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt
@@ -1,6 +1,7 @@
package ru.n08i40k.polytechnic.next.ui.main.schedule
import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.runtime.Composable
@@ -28,7 +29,8 @@ fun DayPager(group: Group = FakeScheduleRepository.exampleGroup) {
HorizontalPager(
state = pagerState,
contentPadding = PaddingValues(horizontal = 20.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.Top,
+ modifier = Modifier.height(600.dp)
) { page ->
DayCard(
modifier = Modifier.graphicsLayer {
@@ -37,8 +39,8 @@ fun DayPager(group: Group = FakeScheduleRepository.exampleGroup) {
lerp(
start = 0.95f, stop = 1f, fraction = 1f - offset.coerceIn(0f, 1f)
).also { scale ->
- scaleX = scale
- scaleY = scale
+ scaleX = 1F - scale + 0.95F
+ scaleY = 1F - scale + 0.95F
}
alpha = lerp(
start = 0.5f, stop = 1f, fraction = 1f - offset.coerceIn(0f, 1f)
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/ScheduleScreen.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/ScheduleScreen.kt
index 580bc15..2fdaffe 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/ScheduleScreen.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/ScheduleScreen.kt
@@ -1,12 +1,8 @@
package ru.n08i40k.polytechnic.next.ui.main.schedule
-import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.height
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
@@ -16,10 +12,7 @@ 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
-import androidx.compose.ui.unit.dp
-import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import ru.n08i40k.polytechnic.next.MainViewModel
import ru.n08i40k.polytechnic.next.R
import ru.n08i40k.polytechnic.next.data.MockAppContainer
import ru.n08i40k.polytechnic.next.ui.LoadingContent
@@ -35,25 +28,20 @@ fun ScheduleScreen(
val uiState by scheduleViewModel.uiState.collectAsStateWithLifecycle()
LoadingContent(
- empty = uiState.isLoading,
+ empty = when (uiState) {
+ is ScheduleUiState.NoSchedule -> uiState.isLoading
+ is ScheduleUiState.HasSchedule -> false
+ },
loading = uiState.isLoading,
onRefresh = { onRefreshSchedule() },
verticalArrangement = Arrangement.Top
) {
when (uiState) {
is ScheduleUiState.HasSchedule -> {
- Box {
- val networkCacheRepository =
- hiltViewModel(LocalContext.current as ComponentActivity)
- .appContainer
- .networkCacheRepository
-
- UpdateInfo(networkCacheRepository)
-
- Column {
- Spacer(modifier = Modifier.height(200.dp))
- DayPager((uiState as ScheduleUiState.HasSchedule).group)
- }
+ Column {
+ val hasSchedule = uiState as ScheduleUiState.HasSchedule
+ UpdateInfo(hasSchedule.lastUpdateAt, hasSchedule.updateDates)
+ DayPager(hasSchedule.group)
}
}
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/UpdateInfo.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/UpdateInfo.kt
index 3986a11..96a1d8e 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/UpdateInfo.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/UpdateInfo.kt
@@ -1,36 +1,26 @@
package ru.n08i40k.polytechnic.next.ui.main.schedule
-import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.MaterialTheme
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.saveable.Saver
-import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import androidx.hilt.navigation.compose.hiltViewModel
-import kotlinx.coroutines.runBlocking
-import ru.n08i40k.polytechnic.next.MainViewModel
import ru.n08i40k.polytechnic.next.R
-import ru.n08i40k.polytechnic.next.data.cache.NetworkCacheRepository
-import ru.n08i40k.polytechnic.next.data.cache.impl.FakeNetworkCacheRepository
+import ru.n08i40k.polytechnic.next.UpdateDates
import ru.n08i40k.polytechnic.next.ui.ExpandableCard
-import ru.n08i40k.polytechnic.next.ui.model.ScheduleViewModel
import java.text.SimpleDateFormat
-import java.util.Calendar
import java.util.Date
import java.util.Locale
@@ -40,24 +30,21 @@ fun Date.toString(format: String, locale: Locale = Locale.getDefault()): String
return formatter.format(this)
}
-fun getCurrentDateTime(): Date {
- return Calendar.getInstance().time
-}
-
val expanded = mutableStateOf(false)
@Preview(showBackground = true)
@Composable
-fun UpdateInfo(networkCacheRepository: NetworkCacheRepository = FakeNetworkCacheRepository()) {
+fun UpdateInfo(
+ lastUpdateAt: Long = 0,
+ updateDates: UpdateDates = UpdateDates.newBuilder().build()
+) {
var expanded by remember { expanded }
- val format = "hh:mm:ss dd.MM.yyyy"
+ val format = "HH:mm:ss dd.MM.yyyy"
- val updateDates = remember { runBlocking { networkCacheRepository.getUpdateDates() } }
-
- val currentDate = remember { getCurrentDateTime().toString(format) }
- val cacheUpdateDate = remember { Date(updateDates.cache).toString(format) }
- val scheduleUpdateDate = remember { Date(updateDates.schedule).toString(format) }
+ val currentDate = Date(lastUpdateAt).toString(format)
+ val cacheUpdateDate = Date(updateDates.cache).toString(format)
+ val scheduleUpdateDate = Date(updateDates.schedule).toString(format)
ExpandableCard(
expanded = expanded,
@@ -69,19 +56,40 @@ fun UpdateInfo(networkCacheRepository: NetworkCacheRepository = FakeNetworkCache
.fillMaxWidth()
.padding(10.dp)
) {
- Row(horizontalArrangement = Arrangement.Center) {
- Text(text = stringResource(R.string.last_local_update) + " - ")
- Text(text = currentDate, fontWeight = FontWeight.Bold)
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(text = stringResource(R.string.last_local_update))
+ Text(
+ text = currentDate,
+ fontWeight = FontWeight.Bold,
+ fontFamily = FontFamily.Monospace
+ )
}
- Row(horizontalArrangement = Arrangement.Center) {
- Text(text = stringResource(R.string.last_server_cache_update) + " - ")
- Text(text = cacheUpdateDate, fontWeight = FontWeight.Bold)
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(text = stringResource(R.string.last_server_cache_update))
+ Text(
+ text = cacheUpdateDate,
+ fontWeight = FontWeight.Bold,
+ fontFamily = FontFamily.Monospace
+ )
}
- Row(horizontalArrangement = Arrangement.Center) {
- Text(text = stringResource(R.string.last_server_schedule_update) + " - ")
- Text(text = scheduleUpdateDate, fontWeight = FontWeight.Bold)
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(text = stringResource(R.string.last_server_schedule_update))
+ Text(
+ text = scheduleUpdateDate,
+ fontWeight = FontWeight.Bold,
+ fontFamily = FontFamily.Monospace
+ )
}
}
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/model/ScheduleViewModel.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/model/ScheduleViewModel.kt
index 07fdc5e..7e45e7c 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/model/ScheduleViewModel.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/model/ScheduleViewModel.kt
@@ -9,9 +9,12 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
+import ru.n08i40k.polytechnic.next.UpdateDates
import ru.n08i40k.polytechnic.next.data.AppContainer
import ru.n08i40k.polytechnic.next.data.MyResult
import ru.n08i40k.polytechnic.next.model.Group
+import java.util.Date
+import java.util.logging.Logger
import javax.inject.Inject
sealed interface ScheduleUiState {
@@ -23,18 +26,22 @@ sealed interface ScheduleUiState {
data class HasSchedule(
val group: Group,
+ val updateDates: UpdateDates,
+ val lastUpdateAt: Long,
override val isLoading: Boolean
) : ScheduleUiState
}
private data class ScheduleViewModelState(
val group: Group? = null,
+ val updateDates: UpdateDates? = null,
+ val lastUpdateAt: Long = 0,
val isLoading: Boolean = false
) {
fun toUiState(): ScheduleUiState = if (group == null) {
ScheduleUiState.NoSchedule(isLoading)
} else {
- ScheduleUiState.HasSchedule(group, isLoading)
+ ScheduleUiState.HasSchedule(group, updateDates!!, lastUpdateAt, isLoading)
}
}
@@ -43,6 +50,7 @@ class ScheduleViewModel @Inject constructor(
appContainer: AppContainer
) : ViewModel() {
private val scheduleRepository = appContainer.scheduleRepository
+ private val networkCacheRepository = appContainer.networkCacheRepository
private val viewModelState = MutableStateFlow(ScheduleViewModelState(isLoading = true))
val uiState = viewModelState
@@ -61,8 +69,23 @@ class ScheduleViewModel @Inject constructor(
viewModelState.update {
when (result) {
- is MyResult.Success -> it.copy(group = result.data, isLoading = false)
- is MyResult.Failure -> it.copy(group = null, isLoading = false)
+ is MyResult.Success -> {
+ val updateDates = networkCacheRepository.getUpdateDates()
+
+ Logger.getLogger("ScheduleViewModel").info("Updating...")
+
+ it.copy(
+ group = result.data,
+ updateDates = updateDates,
+ lastUpdateAt = Date().time,
+ isLoading = false
+ )
+ }
+
+ is MyResult.Failure -> it.copy(
+ group = null,
+ isLoading = false
+ )
}
}
}