Skip to content

Commit 7ec2348

Browse files
committed
Add color picker and fix airing schedule widget showing error when screen is locked
2 parents ab66e6d + 1e19184 commit 7ec2348

File tree

27 files changed

+601
-206
lines changed

27 files changed

+601
-206
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
### Fixed
1313
- Improved text compatibility with system font size settings for better readability across all devices.
14+
- Fix error when browsing media overview after logout
15+
- Add worker for Airing Schedule Widget and store it in data store.
1416

1517
## [v2.0.3] - 2024-11-18
1618
### Added

app/src/debug/kotlin/com/revolgenx/anilib/social/factory/MarkdownFactoryImpl.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ object MarkdownFactoryImpl : MarkdownFactory {
5151
autoPlayGif: Boolean,
5252
markdownCallback: MarkdownCallback
5353
): Markwon {
54-
_markwon = _markwon ?: createMarkdown(
54+
_markwon = createMarkdown(
5555
context,
5656
primaryColor,
5757
autoPlayGif,
@@ -74,7 +74,4 @@ object MarkdownFactoryImpl : MarkdownFactory {
7474

7575
}
7676

77-
override fun destroy() {
78-
_markwon = null
79-
}
8077
}

app/src/main/kotlin/com/revolgenx/anilib/app/ui/activity/MainActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class MainActivity : BaseMainActivity() {
6969
)
7070

7171
CheckWhatsNew()
72-
72+
CheckTokenHasExpired()
7373
SpoilerBottomSheet(
7474
openBottomSheet = viewModel.openSpoilerBottomSheet,
7575
bottomSheetState = bottomSheetState,

app/src/main/kotlin/com/revolgenx/anilib/app/ui/viewmodel/MainActivityViewModel.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.revolgenx.anilib.app.ui.viewmodel
22

3+
import android.content.Context
4+
import android.content.Intent
35
import android.text.Spanned
46
import androidx.compose.runtime.getValue
57
import androidx.compose.runtime.mutableStateOf
@@ -9,9 +11,11 @@ import androidx.lifecycle.viewModelScope
911
import cafe.adriel.voyager.core.annotation.InternalVoyagerApi
1012
import cafe.adriel.voyager.core.screen.Screen
1113
import cafe.adriel.voyager.navigator.Navigator
14+
import com.revolgenx.anilib.app.ui.activity.MainActivity
1215
import com.revolgenx.anilib.common.data.constant.MainPageOrder
1316
import com.revolgenx.anilib.common.data.state.MediaState
1417
import com.revolgenx.anilib.common.data.state.UserState
18+
import com.revolgenx.anilib.common.data.store.AiringScheduleFilterDataStore
1519
import com.revolgenx.anilib.common.data.store.AppPreferencesDataStore
1620
import com.revolgenx.anilib.common.data.store.AppPreferencesDataStore.Companion.mediaCoverImageTypeKey
1721
import com.revolgenx.anilib.common.data.store.AppPreferencesDataStore.Companion.mediaTitleTypeKey
@@ -63,7 +67,9 @@ val mainScreenTabs = listOf(
6367

6468
class MainActivityViewModel(
6569
private val preferencesDataStore: AppPreferencesDataStore,
66-
private val userService: UserService
70+
private val userService: UserService,
71+
private val airingScheduleFilterDataStore: AiringScheduleFilterDataStore,
72+
private val exploreAiringScheduleFilterDataStore: AiringScheduleFilterDataStore
6773
) :
6874
ViewModel() {
6975
val currentAppVersion = preferencesDataStore.currentAppVersion
@@ -131,6 +137,27 @@ class MainActivityViewModel(
131137
}
132138
}.catch {}
133139
.launchIn(viewModelScope)
140+
}
141+
142+
143+
fun logout(context: Context){
144+
launch {
145+
preferencesDataStore.logout()
146+
airingScheduleFilterDataStore.updateData {
147+
it.copy(showOnlyPlanning = false, showOnlyWatching = false)
148+
}
134149

150+
exploreAiringScheduleFilterDataStore.updateData {
151+
it.copy(showOnlyPlanning = false, showOnlyWatching = false)
152+
}
153+
154+
context.startActivity(Intent(context, MainActivity::class.java).apply {
155+
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
156+
})
157+
158+
if (context is MainActivity) {
159+
context.finish()
160+
}
161+
}
135162
}
136163
}

app/src/main/kotlin/com/revolgenx/anilib/common/data/repository/Apollo.kt

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,43 @@ import okhttp3.OkHttpClient
1010
import okhttp3.logging.HttpLoggingInterceptor
1111

1212
object Apollo {
13-
fun provideApolloClient(appPreferencesDataStore: AppPreferencesDataStore): ApolloClient = ApolloClient.Builder()
14-
.okHttpClient(
15-
OkHttpClient.Builder().apply {
16-
if (BuildConfig.DEBUG) {
17-
addInterceptor(HttpLoggingInterceptor().apply {
18-
level = HttpLoggingInterceptor.Level.BODY
19-
})
13+
fun provideApolloClient(appPreferencesDataStore: AppPreferencesDataStore): ApolloClient =
14+
ApolloClient.Builder()
15+
.okHttpClient(
16+
OkHttpClient.Builder().apply {
17+
if (BuildConfig.DEBUG) {
18+
addInterceptor(HttpLoggingInterceptor().apply {
19+
level = HttpLoggingInterceptor.Level.BODY
20+
})
21+
}
2022
}
21-
}
22-
.addInterceptor {
23-
it.proceed(it.request().let { req ->
24-
runBlocking {
23+
.addInterceptor {
24+
it.proceed(it.request().let { req ->
2525
val token = appPreferencesDataStore.token.get()
2626
if (token != null) {
27+
var tokenExpiresAt = appPreferencesDataStore.tokenExpiresAt.get()
28+
if (tokenExpiresAt == null) {
29+
tokenExpiresAt = runBlocking {
30+
appPreferencesDataStore.setTokenExpiresAt(token)
31+
appPreferencesDataStore.tokenExpiresAt.get()!!
32+
}
33+
}
34+
35+
if (tokenExpiresAt < System.currentTimeMillis()) {
36+
appPreferencesDataStore.tokenHasExpired.value = true
37+
}
38+
2739
req.newBuilder()
2840
.addHeader(
2941
"Authorization",
3042
"Bearer $token"
3143
)
3244
.build()
3345
} else req
34-
}
35-
})
36-
}
37-
.build())
38-
.serverUrl(Config.API_URL)
39-
.build()
46+
47+
})
48+
}
49+
.build())
50+
.serverUrl(Config.API_URL)
51+
.build()
4052
}

app/src/main/kotlin/com/revolgenx/anilib/common/data/service/ServiceModule.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import com.revolgenx.anilib.setting.data.service.SettingsService
2323
import com.revolgenx.anilib.setting.data.service.SettingsServiceImpl
2424
import com.revolgenx.anilib.social.data.service.ActivityUnionService
2525
import com.revolgenx.anilib.social.data.service.ActivityUnionServiceImpl
26-
import com.revolgenx.anilib.common.data.service.ToggleServiceImpl
26+
import com.revolgenx.anilib.common.data.store.airingScheduleWidgetDataStore
2727
import com.revolgenx.anilib.common.data.store.genreCollectionDataStore
2828
import com.revolgenx.anilib.common.data.store.mediaTagCollectionDataStore
2929
import com.revolgenx.anilib.staff.data.service.StaffService
@@ -32,6 +32,8 @@ import com.revolgenx.anilib.studio.data.service.StudioService
3232
import com.revolgenx.anilib.studio.data.service.StudioServiceImpl
3333
import com.revolgenx.anilib.user.data.service.UserService
3434
import com.revolgenx.anilib.user.data.service.UserServiceImpl
35+
import com.revolgenx.anilib.widget.data.service.AiringScheduleWidgetService
36+
import org.koin.android.ext.koin.androidContext
3537
import org.koin.core.module.dsl.bind
3638
import org.koin.core.module.dsl.factoryOf
3739
import org.koin.dsl.module
@@ -59,4 +61,5 @@ val serviceModules = module {
5961
)
6062
}
6163
factoryOf(::ToggleServiceImpl) { bind<ToggleService>() }
64+
factory { AiringScheduleWidgetService(get(), get(), androidContext().airingScheduleWidgetDataStore) }
6265
}

app/src/main/kotlin/com/revolgenx/anilib/common/data/store/AppPreferencesDataStore.kt

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.revolgenx.anilib.common.data.store
22

33
import android.content.Context
44
import androidx.compose.runtime.Composable
5+
import androidx.compose.runtime.mutableStateOf
56
import androidx.datastore.core.DataStore
67
import androidx.datastore.preferences.core.Preferences
78
import androidx.datastore.preferences.core.booleanPreferencesKey
@@ -12,26 +13,29 @@ import androidx.datastore.preferences.core.longPreferencesKey
1213
import androidx.datastore.preferences.core.stringPreferencesKey
1314
import anilib.i18n.R
1415
import com.auth0.android.jwt.JWT
15-
import com.revolgenx.anilib.common.util.OnClick
16-
import com.revolgenx.anilib.media.ui.model.MediaCoverImageModel
17-
import com.revolgenx.anilib.media.ui.model.MediaTitleModel
18-
import com.revolgenx.anilib.notification.data.store.NotificationDataStore
19-
import com.revolgenx.anilib.common.data.constant.InterstitialAdsInterval
2016
import com.revolgenx.anilib.common.data.constant.ExploreSectionOrder
17+
import com.revolgenx.anilib.common.data.constant.InterstitialAdsInterval
2118
import com.revolgenx.anilib.common.data.constant.MainPageOrder
2219
import com.revolgenx.anilib.common.data.constant.RewardedInterstitialAdsInterval
2320
import com.revolgenx.anilib.common.ext.get
21+
import com.revolgenx.anilib.common.util.OnClick
22+
import com.revolgenx.anilib.media.ui.model.MediaCoverImageModel
23+
import com.revolgenx.anilib.media.ui.model.MediaTitleModel
24+
import com.revolgenx.anilib.notification.data.store.NotificationDataStore
2425
import com.revolgenx.anilib.setting.ui.component.ListPreferenceEntry
2526
import com.revolgenx.anilib.type.AiringSort
2627
import kotlinx.coroutines.CoroutineScope
2728
import kotlinx.coroutines.flow.map
2829
import kotlinx.coroutines.launch
30+
import java.time.Instant
31+
import java.time.temporal.ChronoUnit
2932

3033
class AppPreferencesDataStore(val dataStore: DataStore<Preferences>) {
3134
val data get() = dataStore.data
3235

3336
companion object {
3437
val authTokenKey = stringPreferencesKey("auth_token_key")
38+
val authTokenExpiresAtKey = longPreferencesKey("auth_token_expires_at_key")
3539
val userIdKey = intPreferencesKey("user_id_key")
3640
val notificationRefreshIntervalKey = intPreferencesKey("notification_refresh_interval_key")
3741
val mediaCoverImageTypeKey = intPreferencesKey("media_cover_image_type_key")
@@ -43,10 +47,14 @@ class AppPreferencesDataStore(val dataStore: DataStore<Preferences>) {
4347
val displayAdultContentKey = booleanPreferencesKey("display_adult_content_key")
4448
val mediaListDisplayModeKey = intPreferencesKey("media_list_display_mode_key")
4549
val otherMediaListDisplayModeKey = intPreferencesKey("other_media_list_display_mode_key")
46-
val displayInterstitialAdsIntervalKey = intPreferencesKey("display_interstitial_ads_interval_key")
47-
val displayRewardedInterstitialAdsIntervalKey = intPreferencesKey("display_rewarded_interstitial_ads_interval_key")
48-
val interstitialAdsDisplayedDateTimeKey = longPreferencesKey("interstitial_ads_displayed_date_time_key")
49-
val rewardedInterstitialAdsDisplayedDateTimeKey = longPreferencesKey("rewarded_interstitial_ads_displayed_date_time_key")
50+
val displayInterstitialAdsIntervalKey =
51+
intPreferencesKey("display_interstitial_ads_interval_key")
52+
val displayRewardedInterstitialAdsIntervalKey =
53+
intPreferencesKey("display_rewarded_interstitial_ads_interval_key")
54+
val interstitialAdsDisplayedDateTimeKey =
55+
longPreferencesKey("interstitial_ads_displayed_date_time_key")
56+
val rewardedInterstitialAdsDisplayedDateTimeKey =
57+
longPreferencesKey("rewarded_interstitial_ads_displayed_date_time_key")
5058
val autoPlayGifKey = booleanPreferencesKey("auto_play_gif_key")
5159
val showUserAboutKey = booleanPreferencesKey("show_user_about_key")
5260
val exploreAiringOrderKey = intPreferencesKey("explore_airing_order_key")
@@ -76,7 +84,8 @@ class AppPreferencesDataStore(val dataStore: DataStore<Preferences>) {
7684
val widgetOnlyWatchingKey = booleanPreferencesKey("widget_only_watching_key")
7785
val widgetOnlyPlanningKey = booleanPreferencesKey("widget_only_planning_key")
7886
val widgetAiringSortKey = intPreferencesKey("widget_airing_sort_key")
79-
val widgetBackgroundSameAsAppKey = booleanPreferencesKey("widget_background_same_as_app_key")
87+
val widgetBackgroundSameAsAppKey =
88+
booleanPreferencesKey("widget_background_same_as_app_key")
8089

8190
val currentAppVersionKey = stringPreferencesKey("current_app_version_key")
8291
val displayScaleKey = floatPreferencesKey("display_scale_key")
@@ -95,6 +104,11 @@ class AppPreferencesDataStore(val dataStore: DataStore<Preferences>) {
95104
prefKey = authTokenKey
96105
)
97106

107+
val tokenExpiresAt = PreferencesDataStore(
108+
dataStore = dataStore,
109+
prefKey = authTokenExpiresAtKey
110+
)
111+
98112
val userId = PreferencesDataStore(
99113
dataStore = dataStore,
100114
prefKey = userIdKey
@@ -277,24 +291,26 @@ class AppPreferencesDataStore(val dataStore: DataStore<Preferences>) {
277291
)
278292

279293
val isLoggedIn = userId.data.map { it != null }
294+
val tokenHasExpired =
295+
mutableStateOf(tokenExpiresAt.get().let { it != null && it < System.currentTimeMillis() })
280296

281297
@Composable
282298
fun isLoggedIn(): Boolean {
283299
return userId.collectAsState().value != null
284300
}
285301

286302
fun getMainPageOrder(mainPageOrder: MainPageOrder): Int {
287-
return when(mainPageOrder){
303+
return when (mainPageOrder) {
288304
MainPageOrder.HOME -> data.map { it[homePageOrderKey] ?: 0 }.get()
289305
MainPageOrder.ANIME -> data.map { it[animePageOrderKey] ?: 1 }.get()
290306
MainPageOrder.MANGA -> data.map { it[mangaPageOrderKey] ?: 2 }.get()
291307
MainPageOrder.ACTIVITY -> data.map { it[activityPageOrderKey] ?: 3 }.get()
292308
}
293309
}
294310

295-
suspend fun setMainPageOrder(mainPageOrder: MainPageOrder, order: Int){
311+
suspend fun setMainPageOrder(mainPageOrder: MainPageOrder, order: Int) {
296312
dataStore.edit {
297-
when(mainPageOrder){
313+
when (mainPageOrder) {
298314
MainPageOrder.HOME -> it[homePageOrderKey] = order
299315
MainPageOrder.ANIME -> it[animePageOrderKey] = order
300316
MainPageOrder.MANGA -> it[mangaPageOrderKey] = order
@@ -305,7 +321,7 @@ class AppPreferencesDataStore(val dataStore: DataStore<Preferences>) {
305321

306322

307323
fun getExploreSectionOrder(exploreSectionOrder: ExploreSectionOrder): Int {
308-
return when(exploreSectionOrder){
324+
return when (exploreSectionOrder) {
309325
ExploreSectionOrder.AIRING -> data.map { it[exploreAiringOrderKey] ?: 0 }.get()
310326
ExploreSectionOrder.TRENDING -> data.map { it[exploreTrendingOrderKey] ?: 1 }.get()
311327
ExploreSectionOrder.POPULAR -> data.map { it[explorePopularOrderKey] ?: 2 }.get()
@@ -315,9 +331,9 @@ class AppPreferencesDataStore(val dataStore: DataStore<Preferences>) {
315331
}
316332
}
317333

318-
suspend fun setExploreSectionOrder(exploreSectionOrder: ExploreSectionOrder, order: Int){
334+
suspend fun setExploreSectionOrder(exploreSectionOrder: ExploreSectionOrder, order: Int) {
319335
dataStore.edit {
320-
when(exploreSectionOrder){
336+
when (exploreSectionOrder) {
321337
ExploreSectionOrder.AIRING -> it[exploreAiringOrderKey] = order
322338
ExploreSectionOrder.TRENDING -> it[exploreTrendingOrderKey] = order
323339
ExploreSectionOrder.POPULAR -> it[explorePopularOrderKey] = order
@@ -329,19 +345,24 @@ class AppPreferencesDataStore(val dataStore: DataStore<Preferences>) {
329345
}
330346

331347
fun isExploreSectionEnabled(exploreSectionOrder: ExploreSectionOrder): Boolean {
332-
return when(exploreSectionOrder){
348+
return when (exploreSectionOrder) {
333349
ExploreSectionOrder.AIRING -> data.map { it[exploreAiringEnabledKey] ?: true }.get()
334350
ExploreSectionOrder.TRENDING -> data.map { it[exploreTrendingEnabledKey] ?: true }.get()
335351
ExploreSectionOrder.POPULAR -> data.map { it[explorePopularEnabledKey] ?: true }.get()
336-
ExploreSectionOrder.NEWLY_ADDED -> data.map { it[exploreNewlyAddedEnabledKey] ?: true }.get()
352+
ExploreSectionOrder.NEWLY_ADDED -> data.map { it[exploreNewlyAddedEnabledKey] ?: true }
353+
.get()
354+
337355
ExploreSectionOrder.WATCHING -> data.map { it[exploreWatchingEnabledKey] ?: true }.get()
338356
ExploreSectionOrder.READING -> data.map { it[exploreReadingEnabledKey] ?: true }.get()
339357
}
340358
}
341359

342-
suspend fun setExploreSectionEnabled(exploreSectionOrder: ExploreSectionOrder,enabled: Boolean){
360+
suspend fun setExploreSectionEnabled(
361+
exploreSectionOrder: ExploreSectionOrder,
362+
enabled: Boolean
363+
) {
343364
dataStore.edit {
344-
when(exploreSectionOrder){
365+
when (exploreSectionOrder) {
345366
ExploreSectionOrder.AIRING -> it[exploreAiringEnabledKey] = enabled
346367
ExploreSectionOrder.TRENDING -> it[exploreTrendingEnabledKey] = enabled
347368
ExploreSectionOrder.POPULAR -> it[explorePopularEnabledKey] = enabled
@@ -367,16 +388,26 @@ class AppPreferencesDataStore(val dataStore: DataStore<Preferences>) {
367388
}
368389

369390
suspend fun login(mToken: String) {
370-
val userId = JWT(mToken).subject!!.trim().toInt()
391+
val jwtToken = JWT(mToken)
392+
val userId = jwtToken.subject!!.trim().toInt()
393+
val expiresAt =
394+
jwtToken.expiresAt?.time ?: Instant.now().plus(364, ChronoUnit.DAYS).toEpochMilli()
395+
371396
dataStore.edit { pref ->
372397
pref[authTokenKey] = mToken
373398
pref[userIdKey] = userId
399+
pref[authTokenExpiresAtKey] = expiresAt
374400
}
375401
}
376402

403+
suspend fun setTokenExpiresAt(token: String){
404+
tokenExpiresAt.set(JWT(token).expiresAt?.time ?: Instant.now().plus(364, ChronoUnit.DAYS).toEpochMilli())
405+
}
406+
377407
suspend fun logout() {
378408
dataStore.edit { pref ->
379409
pref.remove(authTokenKey)
410+
pref.remove(authTokenExpiresAtKey)
380411
pref.remove(userIdKey)
381412
pref.remove(NotificationDataStore.lastShownNotificationIdKey)
382413
pref.remove(displayAdultContentKey)

0 commit comments

Comments
 (0)