Skip to content

Commit 070e271

Browse files
committed
prepare edit dialog
1 parent e97509f commit 070e271

File tree

16 files changed

+176
-98
lines changed

16 files changed

+176
-98
lines changed

anilist/src/commonMain/graphql/AiringQuery.graphql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ query AiringQuery(
7979
}
8080
},
8181
mediaListEntry {
82-
score(format: POINT_5)
82+
score(format: POINT_5),
83+
status
8384
},
8485
trailer {
8586
id,
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
query MediaListEntryQuery($id: Int) {
22
MediaList(mediaId: $id) {
3-
score(format: POINT_5)
3+
score(format: POINT_5),
4+
status
45
}
56
}

anilist/src/commonMain/graphql/MediumQuery.graphql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ query MediumQuery($id: Int, $statusVersion: Int, $html: Boolean) {
6868
}
6969
},
7070
mediaListEntry {
71-
score(format: POINT_5)
71+
score(format: POINT_5),
72+
status
7273
},
7374
trailer {
7475
id,

anilist/src/commonMain/graphql/SeasonQuery.graphql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ query SeasonQuery(
8080
}
8181
},
8282
mediaListEntry {
83-
score(format: POINT_5)
83+
score(format: POINT_5),
84+
status
8485
},
8586
trailer {
8687
id,

anilist/src/commonMain/graphql/TrendingQuery.graphql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ query TrendingQuery(
8383
}
8484
},
8585
mediaListEntry {
86-
score(format: POINT_5)
86+
score(format: POINT_5),
87+
status
8788
},
8889
trailer {
8990
id,

anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/model/Medium.kt

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ package dev.datlag.aniflow.anilist.model
33
import dev.datlag.aniflow.anilist.*
44
import dev.datlag.aniflow.anilist.AdultContent
55
import dev.datlag.aniflow.anilist.common.lastMonth
6-
import dev.datlag.aniflow.anilist.type.MediaFormat
7-
import dev.datlag.aniflow.anilist.type.MediaRankType
8-
import dev.datlag.aniflow.anilist.type.MediaStatus
9-
import dev.datlag.aniflow.anilist.type.MediaType
6+
import dev.datlag.aniflow.anilist.type.*
107
import dev.datlag.aniflow.model.ifValue
118
import dev.datlag.aniflow.model.toInt
129
import kotlinx.datetime.Clock
@@ -379,22 +376,27 @@ data class Medium(
379376

380377
@Serializable
381378
data class Entry(
382-
val score: Double?
379+
val score: Double?,
380+
val status: MediaListStatus
383381
) {
384382
constructor(entry: MediumQuery.MediaListEntry) : this(
385-
score = entry.score
383+
score = entry.score,
384+
status = entry.status ?: MediaListStatus.UNKNOWN__
386385
)
387386

388387
constructor(entry: TrendingQuery.MediaListEntry) : this(
389-
score = entry.score
388+
score = entry.score,
389+
status = entry.status ?: MediaListStatus.UNKNOWN__
390390
)
391391

392392
constructor(entry: AiringQuery.MediaListEntry) : this(
393-
score = entry.score
393+
score = entry.score,
394+
status = entry.status ?: MediaListStatus.UNKNOWN__
394395
)
395396

396397
constructor(entry: SeasonQuery.MediaListEntry) : this(
397-
score = entry.score
398+
score = entry.score,
399+
status = entry.status ?: MediaListStatus.UNKNOWN__
398400
)
399401
}
400402

composeApp/src/commonMain/kotlin/dev/datlag/aniflow/common/ExtendMedium.kt

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package dev.datlag.aniflow.common
22

3+
import androidx.compose.material.icons.Icons
4+
import androidx.compose.material.icons.rounded.*
35
import androidx.compose.runtime.Composable
46
import androidx.compose.runtime.getValue
57
import dev.datlag.aniflow.LocalDI
68
import dev.datlag.aniflow.SharedRes
79
import dev.datlag.aniflow.anilist.model.Character
810
import dev.datlag.aniflow.anilist.model.Medium
9-
import dev.datlag.aniflow.anilist.type.MediaFormat
10-
import dev.datlag.aniflow.anilist.type.MediaRankType
11-
import dev.datlag.aniflow.anilist.type.MediaStatus
11+
import dev.datlag.aniflow.anilist.type.*
1212
import dev.datlag.aniflow.settings.Settings
1313
import dev.datlag.aniflow.settings.model.AppSettings
1414
import dev.datlag.aniflow.trace.model.SearchResponse
@@ -149,4 +149,26 @@ fun SearchResponse.Result.AniList.asMedium(): Medium {
149149
_isAdult = this.isAdult,
150150
title = this.title.asMediumTitle()
151151
)
152-
}
152+
}
153+
154+
fun MediaListStatus.icon() = when (this) {
155+
MediaListStatus.CURRENT -> Icons.Rounded.Edit
156+
MediaListStatus.COMPLETED -> Icons.Rounded.Check
157+
MediaListStatus.PAUSED -> Icons.Rounded.Pause
158+
MediaListStatus.DROPPED -> Icons.Rounded.Close
159+
MediaListStatus.PLANNING -> Icons.Rounded.WatchLater
160+
MediaListStatus.REPEATING -> Icons.Rounded.Replay
161+
else -> Icons.Rounded.Add
162+
}
163+
164+
fun MediaListStatus.stringRes(isManga: Boolean) = when (this) {
165+
MediaListStatus.CURRENT -> if (isManga) SharedRes.strings.reading else SharedRes.strings.watching
166+
MediaListStatus.COMPLETED -> SharedRes.strings.completed
167+
MediaListStatus.PAUSED -> SharedRes.strings.paused
168+
MediaListStatus.DROPPED -> SharedRes.strings.dropped
169+
MediaListStatus.PLANNING -> SharedRes.strings.planning
170+
MediaListStatus.REPEATING -> SharedRes.strings.repeating
171+
else -> SharedRes.strings.add
172+
}
173+
174+
fun MediaListStatus.stringRes(type: MediaType) = this.stringRes(type == MediaType.MANGA)

composeApp/src/commonMain/kotlin/dev/datlag/aniflow/module/NetworkModule.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,14 @@ data object NetworkModule {
165165
}
166166
bindSingleton<CharacterRepository> {
167167
CharacterRepository(
168-
client = instance(Constants.AniList.APOLLO_CLIENT),
169-
fallbackClient = instance(Constants.AniList.FALLBACK_APOLLO_CLIENT),
168+
client = instance<ApolloClient>(Constants.AniList.APOLLO_CLIENT).newBuilder().fetchPolicy(FetchPolicy.NetworkFirst).build(),
169+
fallbackClient = instance<ApolloClient>(Constants.AniList.FALLBACK_APOLLO_CLIENT).newBuilder().fetchPolicy(FetchPolicy.NetworkFirst).build(),
170170
)
171171
}
172172
bindSingleton<MediumRepository> {
173173
MediumRepository(
174-
client = instance(Constants.AniList.APOLLO_CLIENT),
175-
fallbackClient = instance(Constants.AniList.FALLBACK_APOLLO_CLIENT)
174+
client = instance<ApolloClient>(Constants.AniList.APOLLO_CLIENT).newBuilder().fetchPolicy(FetchPolicy.NetworkFirst).build(),
175+
fallbackClient = instance<ApolloClient>(Constants.AniList.FALLBACK_APOLLO_CLIENT).newBuilder().fetchPolicy(FetchPolicy.NetworkFirst).build()
176176
)
177177
}
178178
bindSingleton<TraceRepository> {

composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/DialogConfig.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ sealed class DialogConfig {
1010
data class Character(
1111
val initial: Char
1212
) : DialogConfig()
13+
14+
@Serializable
15+
data object Edit : DialogConfig()
1316
}

composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumComponent.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import dev.datlag.aniflow.anilist.MediumRepository
66
import dev.datlag.aniflow.anilist.model.Character
77
import dev.datlag.aniflow.anilist.model.Medium
88
import dev.datlag.aniflow.anilist.type.MediaFormat
9+
import dev.datlag.aniflow.anilist.type.MediaListStatus
910
import dev.datlag.aniflow.anilist.type.MediaStatus
11+
import dev.datlag.aniflow.anilist.type.MediaType
1012
import dev.datlag.aniflow.other.Series
1113
import dev.datlag.aniflow.settings.model.AppSettings
1214
import dev.datlag.aniflow.ui.navigation.Component
@@ -50,8 +52,8 @@ interface MediumComponent : ContentHolderComponent {
5052
val isFavoriteBlocked: Flow<Boolean>
5153
val siteUrl: Flow<String>
5254

53-
val bsAvailable: Boolean
54-
val bsOptions: Flow<Collection<Series>>
55+
val type: Flow<MediaType>
56+
val listStatus: Flow<MediaListStatus>
5557

5658
val dialog: Value<ChildSlot<DialogConfig, DialogComponent>>
5759

@@ -64,4 +66,5 @@ interface MediumComponent : ContentHolderComponent {
6466
fun descriptionTranslation(text: String?)
6567
fun showCharacter(character: Character)
6668
fun toggleFavorite()
69+
fun edit()
6770
}

composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreen.kt

Lines changed: 13 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import dev.datlag.aniflow.LocalDI
3838
import dev.datlag.aniflow.LocalHaze
3939
import dev.datlag.aniflow.LocalPaddingValues
4040
import dev.datlag.aniflow.SharedRes
41+
import dev.datlag.aniflow.anilist.type.MediaListStatus
4142
import dev.datlag.aniflow.anilist.type.MediaStatus
4243
import dev.datlag.aniflow.common.*
4344
import dev.datlag.aniflow.other.StateSaver
@@ -46,6 +47,7 @@ import dev.datlag.aniflow.ui.custom.EditFAB
4647
import dev.datlag.aniflow.ui.navigation.screen.medium.component.*
4748
import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle
4849
import dev.icerock.moko.resources.compose.painterResource
50+
import dev.icerock.moko.resources.compose.stringResource
4951
import io.github.aakira.napier.Napier
5052
import kotlinx.coroutines.launch
5153
import org.kodein.di.instance
@@ -92,79 +94,24 @@ fun MediumScreen(component: MediumComponent) {
9294
)
9395
},
9496
floatingActionButton = {
95-
val userRating by component.rating.collectAsStateWithLifecycle(-1)
96-
val ratingState = rememberUseCaseState()
97-
val bsState = rememberUseCaseState()
98-
99-
val bsOptions by component.bsOptions.collectAsStateWithLifecycle(emptySet())
100-
101-
val alreadyAdded by component.alreadyAdded.collectAsStateWithLifecycle(
102-
component.initialMedium.entry != null
103-
)
10497
val notReleased by component.status.mapCollect(component.initialMedium.status) {
10598
it == MediaStatus.UNKNOWN__ || it == MediaStatus.NOT_YET_RELEASED
10699
}
107100

108-
RatingDialog(
109-
state = ratingState,
110-
selection = RatingSelection(
111-
onSelectRating = { rating, _ ->
112-
component.rate(rating)
113-
}
114-
),
115-
header = Header.Default(
116-
title = "Rate this Anime",
117-
icon = IconSource(Icons.Filled.Star)
118-
),
119-
body = RatingBody.Default(
120-
bodyText = ""
121-
),
122-
config = RatingConfig(
123-
ratingOptionsCount = 5,
124-
ratingOptionsSelected = userRating.takeIf { it > 0 },
125-
ratingZeroValid = true
126-
)
127-
)
128-
129-
OptionDialog(
130-
state = bsState,
131-
selection = OptionSelection.Single(
132-
options = bsOptions.map {
133-
Option(
134-
titleText = it.title
135-
)
136-
},
137-
onSelectOption = { option, _ ->
138-
Napier.e("Selected: ${bsOptions.toList()[option]}")
139-
}
140-
),
141-
header = Header.Default(
142-
icon = IconSource(
143-
painter = painterResource(SharedRes.images.bs)
144-
),
145-
title = "Connect with BS"
146-
),
147-
config = OptionConfig(
148-
mode = DisplayMode.LIST
149-
)
150-
)
151-
152101
if (!notReleased) {
153-
val uriHandler = LocalUriHandler.current
154-
val userHelper by LocalDI.current.instance<UserHelper>()
102+
val status by component.listStatus.collectAsStateWithLifecycle(component.initialMedium.entry?.status ?: MediaListStatus.UNKNOWN__)
103+
val type by component.type.collectAsStateWithLifecycle(component.initialMedium.type)
155104

156-
EditFAB(
157-
displayAdd = !alreadyAdded,
158-
bsAvailable = component.bsAvailable,
159-
expanded = listState.isScrollingUp(),
160-
onBS = {
161-
bsState.show()
162-
},
163-
onRate = {
164-
uriHandler.openUri(userHelper.loginUrl)
105+
ExtendedFloatingActionButton(
106+
onClick = { component.edit() },
107+
icon = {
108+
Icon(
109+
imageVector = status.icon(),
110+
contentDescription = null,
111+
)
165112
},
166-
onProgress = {
167-
// ratingState.show()
113+
text = {
114+
Text(text = stringResource(status.stringRes(type)))
168115
}
169116
)
170117
}

composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import dev.datlag.aniflow.anilist.*
1414
import dev.datlag.aniflow.anilist.model.Character
1515
import dev.datlag.aniflow.anilist.model.Medium
1616
import dev.datlag.aniflow.anilist.type.MediaFormat
17+
import dev.datlag.aniflow.anilist.type.MediaListStatus
1718
import dev.datlag.aniflow.anilist.type.MediaStatus
1819
import dev.datlag.aniflow.anilist.type.MediaType
1920
import dev.datlag.aniflow.common.*
@@ -26,6 +27,7 @@ import dev.datlag.aniflow.settings.model.AppSettings
2627
import dev.datlag.aniflow.settings.model.CharLanguage
2728
import dev.datlag.aniflow.ui.navigation.DialogComponent
2829
import dev.datlag.aniflow.ui.navigation.screen.medium.dialog.character.CharacterDialogComponent
30+
import dev.datlag.aniflow.ui.navigation.screen.medium.dialog.edit.EditDialogComponent
2931
import dev.datlag.tooling.alsoTrue
3032
import dev.datlag.tooling.async.suspendCatching
3133
import dev.datlag.tooling.compose.ioDispatcher
@@ -70,7 +72,7 @@ class MediumScreenComponent(
7072
override val isAdultAllowed: Flow<Boolean> = appSettings.adultContent
7173

7274
@OptIn(ExperimentalCoroutinesApi::class)
73-
private val type: Flow<MediaType> = mediumSuccessState.mapLatest {
75+
override val type: Flow<MediaType> = mediumSuccessState.mapLatest {
7476
it.medium.type
7577
}
7678

@@ -178,14 +180,9 @@ class MediumScreenComponent(
178180
it.medium.siteUrl
179181
}
180182

181-
private val burningSeriesResolver by di.instance<BurningSeriesResolver>()
182-
183-
override val bsAvailable: Boolean
184-
get() = burningSeriesResolver.isAvailable
185-
186183
@OptIn(ExperimentalCoroutinesApi::class)
187-
override val bsOptions = title.mapLatest {
188-
burningSeriesResolver.resolveByName(it.english, it.romaji)
184+
override val listStatus: Flow<MediaListStatus> = mediumSuccessState.mapLatest {
185+
it.medium.entry?.status ?: MediaListStatus.UNKNOWN__
189186
}
190187

191188
private val dialogNavigation = SlotNavigation<DialogConfig>()
@@ -200,6 +197,12 @@ class MediumScreenComponent(
200197
initialChar = config.initial,
201198
onDismiss = dialogNavigation::dismiss
202199
)
200+
is DialogConfig.Edit -> EditDialogComponent(
201+
componentContext = context,
202+
di = di,
203+
titleFlow = title,
204+
onDismiss = dialogNavigation::dismiss
205+
)
203206
}
204207
}
205208

@@ -294,4 +297,8 @@ class MediumScreenComponent(
294297
aniListClient.mutation(mutation).execute()
295298
}
296299
}
300+
301+
override fun edit() {
302+
dialogNavigation.activate(DialogConfig.Edit)
303+
}
297304
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package dev.datlag.aniflow.ui.navigation.screen.medium.dialog.edit
2+
3+
import dev.datlag.aniflow.other.Series
4+
import dev.datlag.aniflow.ui.navigation.DialogComponent
5+
import kotlinx.coroutines.flow.Flow
6+
7+
interface EditComponent : DialogComponent {
8+
9+
val bsAvailable: Boolean
10+
val bsOptions: Flow<Collection<Series>>
11+
}

0 commit comments

Comments
 (0)