Support for private tracking with AniList and Bangumi (#1736)
Co-authored-by: MajorTanya <39014446+MajorTanya@users.noreply.github.com> Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> (cherry picked from commit 49b2b346b65c2631a8369c8f6643e945720770de) # Conflicts: # CHANGELOG.md # app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt # app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt # app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt # app/src/main/java/eu/kanade/test/DummyTracker.kt
This commit is contained in:
@@ -10,10 +10,12 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.absoluteOffset
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
@@ -22,6 +24,9 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material.icons.filled.VisibilityOff
|
||||
import androidx.compose.material3.Badge
|
||||
import androidx.compose.material3.BadgedBox
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -70,6 +75,7 @@ fun TrackInfoDialogHome(
|
||||
onOpenInBrowser: (TrackItem) -> Unit,
|
||||
onRemoved: (TrackItem) -> Unit,
|
||||
onCopyLink: (TrackItem) -> Unit,
|
||||
onTogglePrivate: (TrackItem) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -84,6 +90,7 @@ fun TrackInfoDialogHome(
|
||||
if (item.track != null) {
|
||||
val supportsScoring = item.tracker.getScoreList().isNotEmpty()
|
||||
val supportsReadingDates = item.tracker.supportsReadingDates
|
||||
val supportsPrivate = item.tracker.supportsPrivateTracking
|
||||
TrackInfoItem(
|
||||
title = item.track.title,
|
||||
tracker = item.tracker,
|
||||
@@ -115,6 +122,9 @@ fun TrackInfoDialogHome(
|
||||
onOpenInBrowser = { onOpenInBrowser(item) },
|
||||
onRemoved = { onRemoved(item) },
|
||||
onCopyLink = { onCopyLink(item) },
|
||||
private = item.track.private,
|
||||
onTogglePrivate = { onTogglePrivate(item) }
|
||||
.takeIf { supportsPrivate },
|
||||
)
|
||||
} else {
|
||||
TrackInfoItemEmpty(
|
||||
@@ -144,17 +154,37 @@ private fun TrackInfoItem(
|
||||
onOpenInBrowser: () -> Unit,
|
||||
onRemoved: () -> Unit,
|
||||
onCopyLink: () -> Unit,
|
||||
private: Boolean,
|
||||
onTogglePrivate: (() -> Unit)?,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
Column {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
TrackLogoIcon(
|
||||
tracker = tracker,
|
||||
onClick = onOpenInBrowser,
|
||||
onLongClick = onCopyLink,
|
||||
)
|
||||
BadgedBox(
|
||||
badge = {
|
||||
if (private) {
|
||||
Badge(
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
modifier = Modifier.absoluteOffset(x = (-5).dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.VisibilityOff,
|
||||
contentDescription = stringResource(MR.strings.tracked_privately),
|
||||
modifier = Modifier.size(14.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
) {
|
||||
TrackLogoIcon(
|
||||
tracker = tracker,
|
||||
onClick = onOpenInBrowser,
|
||||
onLongClick = onCopyLink,
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(48.dp)
|
||||
@@ -181,6 +211,8 @@ private fun TrackInfoItem(
|
||||
onOpenInBrowser = onOpenInBrowser,
|
||||
onRemoved = onRemoved,
|
||||
onCopyLink = onCopyLink,
|
||||
private = private,
|
||||
onTogglePrivate = onTogglePrivate,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -291,6 +323,8 @@ private fun TrackInfoItemMenu(
|
||||
onOpenInBrowser: () -> Unit,
|
||||
onRemoved: () -> Unit,
|
||||
onCopyLink: () -> Unit,
|
||||
private: Boolean,
|
||||
onTogglePrivate: (() -> Unit)?,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) {
|
||||
@@ -318,6 +352,25 @@ private fun TrackInfoItemMenu(
|
||||
expanded = false
|
||||
},
|
||||
)
|
||||
if (onTogglePrivate != null) {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(
|
||||
stringResource(
|
||||
if (private) {
|
||||
MR.strings.action_toggle_private_off
|
||||
} else {
|
||||
MR.strings.action_toggle_private_on
|
||||
},
|
||||
),
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
onTogglePrivate()
|
||||
expanded = false
|
||||
},
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(MR.strings.action_remove)) },
|
||||
onClick = {
|
||||
|
||||
@@ -25,7 +25,9 @@ internal class TrackInfoDialogHomePreviewProvider :
|
||||
remoteUrl = "https://example.com",
|
||||
startDate = 0L,
|
||||
finishDate = 0L,
|
||||
private = false,
|
||||
)
|
||||
private val privateTrack = aTrack.copy(private = true)
|
||||
private val trackItemWithoutTrack = TrackItem(
|
||||
track = null,
|
||||
tracker = DummyTracker(
|
||||
@@ -40,6 +42,13 @@ internal class TrackInfoDialogHomePreviewProvider :
|
||||
name = "Example Tracker 2",
|
||||
),
|
||||
)
|
||||
private val trackItemWithPrivateTrack = TrackItem(
|
||||
track = privateTrack,
|
||||
tracker = DummyTracker(
|
||||
id = 2L,
|
||||
name = "Example Tracker 2",
|
||||
),
|
||||
)
|
||||
|
||||
private val trackersWithAndWithoutTrack = @Composable {
|
||||
TrackInfoDialogHome(
|
||||
@@ -57,6 +66,7 @@ internal class TrackInfoDialogHomePreviewProvider :
|
||||
onOpenInBrowser = {},
|
||||
onRemoved = {},
|
||||
onCopyLink = {},
|
||||
onTogglePrivate = {},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -73,6 +83,24 @@ internal class TrackInfoDialogHomePreviewProvider :
|
||||
onOpenInBrowser = {},
|
||||
onRemoved = {},
|
||||
onCopyLink = {},
|
||||
onTogglePrivate = {},
|
||||
)
|
||||
}
|
||||
|
||||
private val trackerWithPrivateTracking = @Composable {
|
||||
TrackInfoDialogHome(
|
||||
trackItems = listOf(trackItemWithPrivateTrack),
|
||||
dateFormat = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM),
|
||||
onStatusClick = {},
|
||||
onChapterClick = {},
|
||||
onScoreClick = {},
|
||||
onStartDateEdit = {},
|
||||
onEndDateEdit = {},
|
||||
onNewSearch = {},
|
||||
onOpenInBrowser = {},
|
||||
onRemoved = {},
|
||||
onCopyLink = {},
|
||||
onTogglePrivate = {},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -80,5 +108,6 @@ internal class TrackInfoDialogHomePreviewProvider :
|
||||
get() = sequenceOf(
|
||||
trackersWithAndWithoutTrack,
|
||||
noTrackers,
|
||||
trackerWithPrivateTracking,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.VisibilityOff
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
@@ -90,8 +91,9 @@ fun TrackerSearch(
|
||||
queryResult: Result<List<TrackSearch>>?,
|
||||
selected: TrackSearch?,
|
||||
onSelectedChange: (TrackSearch) -> Unit,
|
||||
onConfirmSelection: () -> Unit,
|
||||
onConfirmSelection: (private: Boolean) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
supportsPrivateTracking: Boolean,
|
||||
) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
@@ -164,15 +166,31 @@ fun TrackerSearch(
|
||||
enter = fadeIn() + slideInVertically { it / 2 },
|
||||
exit = slideOutVertically { it / 2 } + fadeOut(),
|
||||
) {
|
||||
Button(
|
||||
onClick = { onConfirmSelection() },
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(12.dp)
|
||||
.padding(MaterialTheme.padding.small)
|
||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||
.fillMaxWidth(),
|
||||
elevation = ButtonDefaults.elevatedButtonElevation(),
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
|
||||
) {
|
||||
Text(text = stringResource(MR.strings.action_track))
|
||||
Button(
|
||||
onClick = { onConfirmSelection(false) },
|
||||
modifier = Modifier.weight(1f),
|
||||
elevation = ButtonDefaults.elevatedButtonElevation(),
|
||||
) {
|
||||
Text(text = stringResource(MR.strings.action_track))
|
||||
}
|
||||
if (supportsPrivateTracking) {
|
||||
Button(
|
||||
onClick = { onConfirmSelection(true) },
|
||||
elevation = ButtonDefaults.elevatedButtonElevation(),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.VisibilityOff,
|
||||
contentDescription = stringResource(MR.strings.action_toggle_private_on),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -20,6 +20,7 @@ internal class TrackerSearchPreviewProvider : PreviewParameterProvider<@Composab
|
||||
onSelectedChange = {},
|
||||
onConfirmSelection = {},
|
||||
onDismissRequest = {},
|
||||
supportsPrivateTracking = false,
|
||||
)
|
||||
}
|
||||
private val fullPageWithoutSelected = @Composable {
|
||||
@@ -31,6 +32,7 @@ internal class TrackerSearchPreviewProvider : PreviewParameterProvider<@Composab
|
||||
onSelectedChange = {},
|
||||
onConfirmSelection = {},
|
||||
onDismissRequest = {},
|
||||
supportsPrivateTracking = false,
|
||||
)
|
||||
}
|
||||
private val loading = @Composable {
|
||||
@@ -42,12 +44,27 @@ internal class TrackerSearchPreviewProvider : PreviewParameterProvider<@Composab
|
||||
onSelectedChange = {},
|
||||
onConfirmSelection = {},
|
||||
onDismissRequest = {},
|
||||
supportsPrivateTracking = false,
|
||||
)
|
||||
}
|
||||
private val fullPageWithPrivateTracking = @Composable {
|
||||
val items = someTrackSearches().take(30).toList()
|
||||
TrackerSearch(
|
||||
state = TextFieldState(initialText = "search text"),
|
||||
onDispatchQuery = {},
|
||||
queryResult = Result.success(items),
|
||||
selected = items[1],
|
||||
onSelectedChange = {},
|
||||
onConfirmSelection = {},
|
||||
onDismissRequest = {},
|
||||
supportsPrivateTracking = true,
|
||||
)
|
||||
}
|
||||
override val values: Sequence<@Composable () -> Unit> = sequenceOf(
|
||||
fullPageWithSecondSelected,
|
||||
fullPageWithoutSelected,
|
||||
loading,
|
||||
fullPageWithPrivateTracking,
|
||||
)
|
||||
|
||||
private fun someTrackSearches(): Sequence<TrackSearch> = sequence {
|
||||
|
||||
Reference in New Issue
Block a user