From 6d1e520c6c5c3860bbd588677bb4a05ab06fe830 Mon Sep 17 00:00:00 2001 From: Caleb Morris Date: Sun, 22 Oct 2023 06:30:34 -0700 Subject: [PATCH] [dev QoL] Added AndroidStudio previews for [presentation.track] namespace (#10022) * Created DummyTracker for use in tests and presentation previews * Added previews for TrackerSearch * Added previews for TrackLogoIcon * Added preview for TrackInfoDialogSelector * Added previews for TrackInfoDialogHome --- .../presentation/track/TrackInfoDialogHome.kt | 14 +++ .../TrackInfoDialogHomePreviewProvider.kt | 81 ++++++++++++ .../track/TrackInfoDialogSelector.kt | 24 ++++ .../presentation/track/TrackerSearch.kt | 12 ++ .../track/TrackerSearchPreviewProvider.kt | 84 +++++++++++++ .../track/components/TrackLogoIcon.kt | 17 +++ .../TrackLogoIconPreviewProvider.kt | 20 +++ .../tachiyomi/dev/preview/DummyTracker.kt | 115 ++++++++++++++++++ 8 files changed, 367 insertions(+) create mode 100644 app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt create mode 100644 app/src/main/java/eu/kanade/presentation/track/TrackerSearchPreviewProvider.kt create mode 100644 app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt index bf7860147..d0b31ca06 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt @@ -44,14 +44,17 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import eu.kanade.domain.track.model.toDbTrack import eu.kanade.presentation.components.DropdownMenu +import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.presentation.track.components.TrackLogoIcon import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.ui.manga.track.TrackItem import eu.kanade.tachiyomi.util.system.copyToClipboard +import tachiyomi.presentation.core.util.ThemePreviews import java.text.DateFormat private const val UnsetStatusTextAlpha = 0.5F @@ -168,6 +171,7 @@ private fun TrackInfoItem( maxLines = 1, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurface, ) } VerticalDivider() @@ -254,6 +258,7 @@ private fun TrackDetailsItem( overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.bodyMedium, textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurface, ) } } @@ -312,3 +317,12 @@ private fun TrackInfoItemMenu( } } } + +@ThemePreviews +@Composable +private fun TrackInfoDialogHomePreviews( + @PreviewParameter(TrackInfoDialogHomePreviewProvider::class) + content: @Composable () -> Unit, +) { + TachiyomiTheme { content() } +} diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt new file mode 100644 index 000000000..00ef15ff1 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHomePreviewProvider.kt @@ -0,0 +1,81 @@ +package eu.kanade.presentation.track + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import eu.kanade.tachiyomi.dev.preview.DummyTracker +import eu.kanade.tachiyomi.ui.manga.track.TrackItem +import tachiyomi.domain.track.model.Track +import java.text.DateFormat + +internal class TrackInfoDialogHomePreviewProvider : + PreviewParameterProvider<@Composable () -> Unit> { + + private val aTrack = Track( + id = 1L, + mangaId = 2L, + syncId = 3L, + remoteId = 4L, + libraryId = null, + title = "Manage Name On Tracker Site", + lastChapterRead = 2.0, + totalChapters = 12L, + status = 1L, + score = 2.0, + remoteUrl = "https://example.com", + startDate = 0L, + finishDate = 0L, + ) + private val trackItemWithoutTrack = TrackItem( + track = null, + tracker = DummyTracker( + id = 1L, + name = "Example Tracker", + ), + ) + private val trackItemWithTrack = TrackItem( + track = aTrack, + tracker = DummyTracker( + id = 2L, + name = "Example Tracker 2", + ), + ) + + private val trackersWithAndWithoutTrack = @Composable { + TrackInfoDialogHome( + trackItems = listOf( + trackItemWithoutTrack, + trackItemWithTrack, + ), + dateFormat = DateFormat.getDateInstance(), + onStatusClick = {}, + onChapterClick = {}, + onScoreClick = {}, + onStartDateEdit = {}, + onEndDateEdit = {}, + onNewSearch = {}, + onOpenInBrowser = {}, + onRemoved = {}, + ) + } + + private val noTrackers = @Composable { + TrackInfoDialogHome( + trackItems = listOf(), + dateFormat = DateFormat.getDateInstance(), + onStatusClick = {}, + onChapterClick = {}, + onScoreClick = {}, + onStartDateEdit = {}, + onEndDateEdit = {}, + onNewSearch = {}, + onOpenInBrowser = {}, + onRemoved = {}, + ) + } + + override val values: Sequence<@Composable () -> Unit> + get() = sequenceOf( + trackersWithAndWithoutTrack, + noTrackers, + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt index 42ff82007..b3afd2b28 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogSelector.kt @@ -30,12 +30,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.components.WheelNumberPicker import tachiyomi.presentation.core.components.WheelTextPicker import tachiyomi.presentation.core.components.material.AlertDialogContent import tachiyomi.presentation.core.components.material.padding +import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.isScrolledToEnd import tachiyomi.presentation.core.util.isScrolledToStart @@ -218,3 +220,25 @@ private fun BaseSelector( }, ) } + +@ThemePreviews +@Composable +private fun TrackStatusSelectorPreviews() { + TachiyomiTheme { + TrackStatusSelector( + selection = 1, + onSelectionChange = {}, + selections = mapOf( + // Anilist values + 1 to R.string.reading, + 2 to R.string.plan_to_read, + 3 to R.string.completed, + 4 to R.string.on_hold, + 5 to R.string.dropped, + 6 to R.string.repeating, + ), + onConfirm = {}, + onDismissRequest = {}, + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt index 8781faaa0..591d371cf 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackerSearch.kt @@ -57,8 +57,10 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.toLowerCase +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import eu.kanade.presentation.manga.components.MangaCover +import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.model.TrackSearch import tachiyomi.presentation.core.components.ScrollbarLazyColumn @@ -66,6 +68,7 @@ import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.screens.EmptyScreen import tachiyomi.presentation.core.screens.LoadingScreen +import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.plus import tachiyomi.presentation.core.util.runOnEnterKeyPressed import tachiyomi.presentation.core.util.secondaryItemAlpha @@ -316,3 +319,12 @@ private fun SearchResultItemDetails( ) } } + +@ThemePreviews +@Composable +private fun TrackerSearchPreviews( + @PreviewParameter(TrackerSearchPreviewProvider::class) + content: @Composable () -> Unit, +) { + TachiyomiTheme { content() } +} diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackerSearchPreviewProvider.kt b/app/src/main/java/eu/kanade/presentation/track/TrackerSearchPreviewProvider.kt new file mode 100644 index 000000000..b945e2ad4 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/track/TrackerSearchPreviewProvider.kt @@ -0,0 +1,84 @@ +package eu.kanade.presentation.track + +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.tooling.preview.datasource.LoremIpsum +import eu.kanade.tachiyomi.data.track.model.TrackSearch +import java.time.Instant +import java.time.temporal.ChronoUnit +import kotlin.random.Random + +internal class TrackerSearchPreviewProvider : PreviewParameterProvider<@Composable () -> Unit> { + private val fullPageWithSecondSelected = @Composable { + val items = someTrackSearches().take(30).toList() + TrackerSearch( + query = TextFieldValue(text = "search text"), + onQueryChange = {}, + onDispatchQuery = {}, + queryResult = Result.success(items), + selected = items[1], + onSelectedChange = {}, + onConfirmSelection = {}, + onDismissRequest = {}, + ) + } + private val fullPageWithoutSelected = @Composable { + TrackerSearch( + query = TextFieldValue(text = ""), + onQueryChange = {}, + onDispatchQuery = {}, + queryResult = Result.success(someTrackSearches().take(30).toList()), + selected = null, + onSelectedChange = {}, + onConfirmSelection = {}, + onDismissRequest = {}, + ) + } + private val loading = @Composable { + TrackerSearch( + query = TextFieldValue(), + onQueryChange = {}, + onDispatchQuery = {}, + queryResult = null, + selected = null, + onSelectedChange = {}, + onConfirmSelection = {}, + onDismissRequest = {}, + ) + } + override val values: Sequence<@Composable () -> Unit> = sequenceOf( + fullPageWithSecondSelected, + fullPageWithoutSelected, + loading, + ) + + private fun someTrackSearches(): Sequence = sequence { + while (true) { + yield(randTrackSearch()) + } + } + + private fun randTrackSearch() = TrackSearch().let { + it.id = Random.nextLong() + it.manga_id = Random.nextLong() + it.sync_id = Random.nextInt() + it.media_id = Random.nextLong() + it.library_id = Random.nextLong() + it.title = lorem((1..10).random()).joinToString() + it.last_chapter_read = (0..100).random().toFloat() + it.total_chapters = (100..1000).random() + it.score = (0..10).random().toFloat() + it.status = Random.nextInt() + it.started_reading_date = 0L + it.finished_reading_date = 0L + it.tracking_url = "https://example.com/tracker-example" + it.cover_url = "https://example.com/cover.png" + it.start_date = Instant.now().minus((1L..365).random(), ChronoUnit.DAYS).toString() + it.summary = lorem((0..40).random()).joinToString() + it + } + + private fun lorem(words: Int): Sequence = + LoremIpsum(words).values +} diff --git a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt index 52bf66575..63b7c6d02 100644 --- a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt +++ b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt @@ -11,8 +11,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.data.track.Tracker +import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.clickableNoIndication @Composable @@ -39,3 +42,17 @@ fun TrackLogoIcon( ) } } + +@ThemePreviews +@Composable +private fun TrackLogoIconPreviews( + @PreviewParameter(TrackLogoIconPreviewProvider::class) + tracker: Tracker, +) { + TachiyomiTheme { + TrackLogoIcon( + tracker = tracker, + onClick = null, + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt new file mode 100644 index 000000000..aeaa577a1 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt @@ -0,0 +1,20 @@ +package eu.kanade.presentation.track.components + +import android.graphics.Color +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.dev.preview.DummyTracker + +internal class TrackLogoIconPreviewProvider : PreviewParameterProvider { + + override val values: Sequence + get() = sequenceOf( + DummyTracker( + id = 1L, + name = "Dummy Tracker", + valLogoColor = Color.rgb(18, 25, 35), + valLogo = R.drawable.ic_tracker_anilist, + ), + ) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt new file mode 100644 index 000000000..2315912ba --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/dev/preview/DummyTracker.kt @@ -0,0 +1,115 @@ +package eu.kanade.tachiyomi.dev.preview + +import android.graphics.Color +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.data.track.model.TrackSearch +import okhttp3.OkHttpClient +import tachiyomi.domain.track.model.Track + +data class DummyTracker( + override val id: Long, + override val name: String, + override val supportsReadingDates: Boolean = false, + override val isLoggedIn: Boolean = false, + val valLogoColor: Int = Color.rgb(18, 25, 35), + val valLogo: Int = R.drawable.ic_tracker_anilist, + val valStatuses: List = (1..6).toList(), + val valReadingStatus: Int = 1, + val valRereadingStatus: Int = 1, + val valCompletionStatus: Int = 2, + val valScoreList: List = (0..10).map(Int::toString), + val val10PointScore: Double = 5.4, + val valSearchResults: List = listOf(), +) : Tracker { + + override val client: OkHttpClient + get() = TODO("Not yet implemented") + + override fun getLogoColor(): Int = valLogoColor + + override fun getLogo(): Int = valLogo + + override fun getStatusList(): List = valStatuses + + override fun getStatus(status: Int): Int? = when (status) { + 1 -> R.string.reading + 2 -> R.string.plan_to_read + 3 -> R.string.completed + 4 -> R.string.on_hold + 5 -> R.string.dropped + 6 -> R.string.repeating + else -> null + } + + override fun getReadingStatus(): Int = valReadingStatus + + override fun getRereadingStatus(): Int = valRereadingStatus + + override fun getCompletionStatus(): Int = valCompletionStatus + + override fun getScoreList(): List = valScoreList + + override fun get10PointScore(track: Track): Double = val10PointScore + + override fun indexToScore(index: Int): Float = getScoreList()[index].toFloat() + + override fun displayScore(track: eu.kanade.tachiyomi.data.database.models.Track): String = + track.score.toString() + + override suspend fun update( + track: eu.kanade.tachiyomi.data.database.models.Track, + didReadChapter: Boolean, + ): eu.kanade.tachiyomi.data.database.models.Track = track + + override suspend fun bind( + track: eu.kanade.tachiyomi.data.database.models.Track, + hasReadChapters: Boolean, + ): eu.kanade.tachiyomi.data.database.models.Track = track + + override suspend fun search(query: String): List = valSearchResults + + override suspend fun refresh( + track: eu.kanade.tachiyomi.data.database.models.Track, + ): eu.kanade.tachiyomi.data.database.models.Track = track + + override suspend fun login(username: String, password: String) = Unit + + override fun logout() = Unit + + override fun getUsername(): String = "username" + + override fun getPassword(): String = "passw0rd" + + override fun saveCredentials(username: String, password: String) = Unit + + override suspend fun register( + item: eu.kanade.tachiyomi.data.database.models.Track, + mangaId: Long, + ) = Unit + + override suspend fun setRemoteStatus( + track: eu.kanade.tachiyomi.data.database.models.Track, + status: Int, + ) = Unit + + override suspend fun setRemoteLastChapterRead( + track: eu.kanade.tachiyomi.data.database.models.Track, + chapterNumber: Int, + ) = Unit + + override suspend fun setRemoteScore( + track: eu.kanade.tachiyomi.data.database.models.Track, + scoreString: String, + ) = Unit + + override suspend fun setRemoteStartDate( + track: eu.kanade.tachiyomi.data.database.models.Track, + epochMillis: Long, + ) = Unit + + override suspend fun setRemoteFinishDate( + track: eu.kanade.tachiyomi.data.database.models.Track, + epochMillis: Long, + ) = Unit +}