mirror of
https://github.com/mihonapp/mihon.git
synced 2025-03-01 18:34:13 +01:00
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>
This commit is contained in:
parent
badc229a23
commit
49b2b346b6
@ -16,6 +16,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
|
|||||||
- Added option to enable incognito per extension ([@sdaqo](https://github.com/sdaqo), [@AntsyLich](https://github.com/AntsyLich)) ([#157](https://github.com/mihonapp/mihon/pull/157))
|
- Added option to enable incognito per extension ([@sdaqo](https://github.com/sdaqo), [@AntsyLich](https://github.com/AntsyLich)) ([#157](https://github.com/mihonapp/mihon/pull/157))
|
||||||
- Add button to favorite manga from history screen ([@Animeboynz](https://github.com/Animeboynz)) ([#1733](https://github.com/mihonapp/mihon/pull/1733))
|
- Add button to favorite manga from history screen ([@Animeboynz](https://github.com/Animeboynz)) ([#1733](https://github.com/mihonapp/mihon/pull/1733))
|
||||||
- Add Monochrome theme (made with e-ink displays in mind) ([@MajorTanya](https://github.com/MajorTanya)) ([#1752](https://github.com/mihonapp/mihon/pull/1752))
|
- Add Monochrome theme (made with e-ink displays in mind) ([@MajorTanya](https://github.com/MajorTanya)) ([#1752](https://github.com/mihonapp/mihon/pull/1752))
|
||||||
|
- Support for private tracking with AniList and Bangumi ([@NarwhalHorns](https://github.com/NarwhalHorns)) ([#1736](https://github.com/mihonapp/mihon/pull/1736))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Apply "Downloaded only" filter to all entries regardless of favourite status ([@NGB-Was-Taken](https://github.com/NGB-Was-Taken)) ([#1603](https://github.com/mihonapp/mihon/pull/1603))
|
- Apply "Downloaded only" filter to all entries regardless of favourite status ([@NGB-Was-Taken](https://github.com/NGB-Was-Taken)) ([#1603](https://github.com/mihonapp/mihon/pull/1603))
|
||||||
|
@ -10,6 +10,7 @@ fun Track.copyPersonalFrom(other: Track): Track {
|
|||||||
status = other.status,
|
status = other.status,
|
||||||
startDate = other.startDate,
|
startDate = other.startDate,
|
||||||
finishDate = other.finishDate,
|
finishDate = other.finishDate,
|
||||||
|
private = other.private,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ fun Track.toDbTrack(): DbTrack = DbTrack.create(trackerId).also {
|
|||||||
it.tracking_url = remoteUrl
|
it.tracking_url = remoteUrl
|
||||||
it.started_reading_date = startDate
|
it.started_reading_date = startDate
|
||||||
it.finished_reading_date = finishDate
|
it.finished_reading_date = finishDate
|
||||||
|
it.private = private
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DbTrack.toDomainTrack(idRequired: Boolean = true): Track? {
|
fun DbTrack.toDomainTrack(idRequired: Boolean = true): Track? {
|
||||||
@ -44,5 +46,6 @@ fun DbTrack.toDomainTrack(idRequired: Boolean = true): Track? {
|
|||||||
remoteUrl = tracking_url,
|
remoteUrl = tracking_url,
|
||||||
startDate = started_reading_date,
|
startDate = started_reading_date,
|
||||||
finishDate = finished_reading_date,
|
finishDate = finished_reading_date,
|
||||||
|
private = private,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,12 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.IntrinsicSize
|
import androidx.compose.foundation.layout.IntrinsicSize
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.absoluteOffset
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.systemBars
|
import androidx.compose.foundation.layout.systemBars
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.layout.wrapContentSize
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
@ -22,6 +24,9 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
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.DropdownMenuItem
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@ -70,6 +75,7 @@ fun TrackInfoDialogHome(
|
|||||||
onOpenInBrowser: (TrackItem) -> Unit,
|
onOpenInBrowser: (TrackItem) -> Unit,
|
||||||
onRemoved: (TrackItem) -> Unit,
|
onRemoved: (TrackItem) -> Unit,
|
||||||
onCopyLink: (TrackItem) -> Unit,
|
onCopyLink: (TrackItem) -> Unit,
|
||||||
|
onTogglePrivate: (TrackItem) -> Unit,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -84,6 +90,7 @@ fun TrackInfoDialogHome(
|
|||||||
if (item.track != null) {
|
if (item.track != null) {
|
||||||
val supportsScoring = item.tracker.getScoreList().isNotEmpty()
|
val supportsScoring = item.tracker.getScoreList().isNotEmpty()
|
||||||
val supportsReadingDates = item.tracker.supportsReadingDates
|
val supportsReadingDates = item.tracker.supportsReadingDates
|
||||||
|
val supportsPrivate = item.tracker.supportsPrivateTracking
|
||||||
TrackInfoItem(
|
TrackInfoItem(
|
||||||
title = item.track.title,
|
title = item.track.title,
|
||||||
tracker = item.tracker,
|
tracker = item.tracker,
|
||||||
@ -115,6 +122,9 @@ fun TrackInfoDialogHome(
|
|||||||
onOpenInBrowser = { onOpenInBrowser(item) },
|
onOpenInBrowser = { onOpenInBrowser(item) },
|
||||||
onRemoved = { onRemoved(item) },
|
onRemoved = { onRemoved(item) },
|
||||||
onCopyLink = { onCopyLink(item) },
|
onCopyLink = { onCopyLink(item) },
|
||||||
|
private = item.track.private,
|
||||||
|
onTogglePrivate = { onTogglePrivate(item) }
|
||||||
|
.takeIf { supportsPrivate },
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
TrackInfoItemEmpty(
|
TrackInfoItemEmpty(
|
||||||
@ -144,17 +154,37 @@ private fun TrackInfoItem(
|
|||||||
onOpenInBrowser: () -> Unit,
|
onOpenInBrowser: () -> Unit,
|
||||||
onRemoved: () -> Unit,
|
onRemoved: () -> Unit,
|
||||||
onCopyLink: () -> Unit,
|
onCopyLink: () -> Unit,
|
||||||
|
private: Boolean,
|
||||||
|
onTogglePrivate: (() -> Unit)?,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Column {
|
Column {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
TrackLogoIcon(
|
BadgedBox(
|
||||||
tracker = tracker,
|
badge = {
|
||||||
onClick = onOpenInBrowser,
|
if (private) {
|
||||||
onLongClick = onCopyLink,
|
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(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(48.dp)
|
.height(48.dp)
|
||||||
@ -181,6 +211,8 @@ private fun TrackInfoItem(
|
|||||||
onOpenInBrowser = onOpenInBrowser,
|
onOpenInBrowser = onOpenInBrowser,
|
||||||
onRemoved = onRemoved,
|
onRemoved = onRemoved,
|
||||||
onCopyLink = onCopyLink,
|
onCopyLink = onCopyLink,
|
||||||
|
private = private,
|
||||||
|
onTogglePrivate = onTogglePrivate,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +323,8 @@ private fun TrackInfoItemMenu(
|
|||||||
onOpenInBrowser: () -> Unit,
|
onOpenInBrowser: () -> Unit,
|
||||||
onRemoved: () -> Unit,
|
onRemoved: () -> Unit,
|
||||||
onCopyLink: () -> Unit,
|
onCopyLink: () -> Unit,
|
||||||
|
private: Boolean,
|
||||||
|
onTogglePrivate: (() -> Unit)?,
|
||||||
) {
|
) {
|
||||||
var expanded by remember { mutableStateOf(false) }
|
var expanded by remember { mutableStateOf(false) }
|
||||||
Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) {
|
Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) {
|
||||||
@ -318,6 +352,25 @@ private fun TrackInfoItemMenu(
|
|||||||
expanded = false
|
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(
|
DropdownMenuItem(
|
||||||
text = { Text(stringResource(MR.strings.action_remove)) },
|
text = { Text(stringResource(MR.strings.action_remove)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
|
@ -25,7 +25,9 @@ internal class TrackInfoDialogHomePreviewProvider :
|
|||||||
remoteUrl = "https://example.com",
|
remoteUrl = "https://example.com",
|
||||||
startDate = 0L,
|
startDate = 0L,
|
||||||
finishDate = 0L,
|
finishDate = 0L,
|
||||||
|
private = false,
|
||||||
)
|
)
|
||||||
|
private val privateTrack = aTrack.copy(private = true)
|
||||||
private val trackItemWithoutTrack = TrackItem(
|
private val trackItemWithoutTrack = TrackItem(
|
||||||
track = null,
|
track = null,
|
||||||
tracker = DummyTracker(
|
tracker = DummyTracker(
|
||||||
@ -40,6 +42,13 @@ internal class TrackInfoDialogHomePreviewProvider :
|
|||||||
name = "Example Tracker 2",
|
name = "Example Tracker 2",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
private val trackItemWithPrivateTrack = TrackItem(
|
||||||
|
track = privateTrack,
|
||||||
|
tracker = DummyTracker(
|
||||||
|
id = 2L,
|
||||||
|
name = "Example Tracker 2",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
private val trackersWithAndWithoutTrack = @Composable {
|
private val trackersWithAndWithoutTrack = @Composable {
|
||||||
TrackInfoDialogHome(
|
TrackInfoDialogHome(
|
||||||
@ -57,6 +66,7 @@ internal class TrackInfoDialogHomePreviewProvider :
|
|||||||
onOpenInBrowser = {},
|
onOpenInBrowser = {},
|
||||||
onRemoved = {},
|
onRemoved = {},
|
||||||
onCopyLink = {},
|
onCopyLink = {},
|
||||||
|
onTogglePrivate = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +83,24 @@ internal class TrackInfoDialogHomePreviewProvider :
|
|||||||
onOpenInBrowser = {},
|
onOpenInBrowser = {},
|
||||||
onRemoved = {},
|
onRemoved = {},
|
||||||
onCopyLink = {},
|
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(
|
get() = sequenceOf(
|
||||||
trackersWithAndWithoutTrack,
|
trackersWithAndWithoutTrack,
|
||||||
noTrackers,
|
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.automirrored.outlined.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.CheckCircle
|
import androidx.compose.material.icons.filled.CheckCircle
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
|
import androidx.compose.material.icons.filled.VisibilityOff
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
@ -90,8 +91,9 @@ fun TrackerSearch(
|
|||||||
queryResult: Result<List<TrackSearch>>?,
|
queryResult: Result<List<TrackSearch>>?,
|
||||||
selected: TrackSearch?,
|
selected: TrackSearch?,
|
||||||
onSelectedChange: (TrackSearch) -> Unit,
|
onSelectedChange: (TrackSearch) -> Unit,
|
||||||
onConfirmSelection: () -> Unit,
|
onConfirmSelection: (private: Boolean) -> Unit,
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
|
supportsPrivateTracking: Boolean,
|
||||||
) {
|
) {
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
@ -164,15 +166,31 @@ fun TrackerSearch(
|
|||||||
enter = fadeIn() + slideInVertically { it / 2 },
|
enter = fadeIn() + slideInVertically { it / 2 },
|
||||||
exit = slideOutVertically { it / 2 } + fadeOut(),
|
exit = slideOutVertically { it / 2 } + fadeOut(),
|
||||||
) {
|
) {
|
||||||
Button(
|
Row(
|
||||||
onClick = { onConfirmSelection() },
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(12.dp)
|
.padding(MaterialTheme.padding.small)
|
||||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||||
.fillMaxWidth(),
|
.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 = {},
|
onSelectedChange = {},
|
||||||
onConfirmSelection = {},
|
onConfirmSelection = {},
|
||||||
onDismissRequest = {},
|
onDismissRequest = {},
|
||||||
|
supportsPrivateTracking = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
private val fullPageWithoutSelected = @Composable {
|
private val fullPageWithoutSelected = @Composable {
|
||||||
@ -31,6 +32,7 @@ internal class TrackerSearchPreviewProvider : PreviewParameterProvider<@Composab
|
|||||||
onSelectedChange = {},
|
onSelectedChange = {},
|
||||||
onConfirmSelection = {},
|
onConfirmSelection = {},
|
||||||
onDismissRequest = {},
|
onDismissRequest = {},
|
||||||
|
supportsPrivateTracking = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
private val loading = @Composable {
|
private val loading = @Composable {
|
||||||
@ -42,12 +44,27 @@ internal class TrackerSearchPreviewProvider : PreviewParameterProvider<@Composab
|
|||||||
onSelectedChange = {},
|
onSelectedChange = {},
|
||||||
onConfirmSelection = {},
|
onConfirmSelection = {},
|
||||||
onDismissRequest = {},
|
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(
|
override val values: Sequence<@Composable () -> Unit> = sequenceOf(
|
||||||
fullPageWithSecondSelected,
|
fullPageWithSecondSelected,
|
||||||
fullPageWithoutSelected,
|
fullPageWithoutSelected,
|
||||||
loading,
|
loading,
|
||||||
|
fullPageWithPrivateTracking,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun someTrackSearches(): Sequence<TrackSearch> = sequence {
|
private fun someTrackSearches(): Sequence<TrackSearch> = sequence {
|
||||||
|
@ -25,6 +25,7 @@ data class BackupTracking(
|
|||||||
@ProtoNumber(10) var startedReadingDate: Long = 0,
|
@ProtoNumber(10) var startedReadingDate: Long = 0,
|
||||||
// finishedReadingDate is called endReadTime in 1.x
|
// finishedReadingDate is called endReadTime in 1.x
|
||||||
@ProtoNumber(11) var finishedReadingDate: Long = 0,
|
@ProtoNumber(11) var finishedReadingDate: Long = 0,
|
||||||
|
@ProtoNumber(12) var private: Boolean = false,
|
||||||
@ProtoNumber(100) var mediaId: Long = 0,
|
@ProtoNumber(100) var mediaId: Long = 0,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -48,6 +49,7 @@ data class BackupTracking(
|
|||||||
startDate = this@BackupTracking.startedReadingDate,
|
startDate = this@BackupTracking.startedReadingDate,
|
||||||
finishDate = this@BackupTracking.finishedReadingDate,
|
finishDate = this@BackupTracking.finishedReadingDate,
|
||||||
remoteUrl = this@BackupTracking.trackingUrl,
|
remoteUrl = this@BackupTracking.trackingUrl,
|
||||||
|
private = this@BackupTracking.private,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +68,7 @@ val backupTrackMapper = {
|
|||||||
remoteUrl: String,
|
remoteUrl: String,
|
||||||
startDate: Long,
|
startDate: Long,
|
||||||
finishDate: Long,
|
finishDate: Long,
|
||||||
|
private: Boolean,
|
||||||
->
|
->
|
||||||
BackupTracking(
|
BackupTracking(
|
||||||
syncId = syncId.toInt(),
|
syncId = syncId.toInt(),
|
||||||
@ -80,5 +83,6 @@ val backupTrackMapper = {
|
|||||||
startedReadingDate = startDate,
|
startedReadingDate = startDate,
|
||||||
finishedReadingDate = finishDate,
|
finishedReadingDate = finishDate,
|
||||||
trackingUrl = remoteUrl,
|
trackingUrl = remoteUrl,
|
||||||
|
private = private,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -404,6 +404,7 @@ class MangaRestorer(
|
|||||||
track.remoteUrl,
|
track.remoteUrl,
|
||||||
track.startDate,
|
track.startDate,
|
||||||
track.finishDate,
|
track.finishDate,
|
||||||
|
track.private,
|
||||||
track.id,
|
track.id,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -32,12 +32,15 @@ interface Track : Serializable {
|
|||||||
|
|
||||||
var tracking_url: String
|
var tracking_url: String
|
||||||
|
|
||||||
fun copyPersonalFrom(other: Track) {
|
var private: Boolean
|
||||||
|
|
||||||
|
fun copyPersonalFrom(other: Track, copyRemotePrivate: Boolean = true) {
|
||||||
last_chapter_read = other.last_chapter_read
|
last_chapter_read = other.last_chapter_read
|
||||||
score = other.score
|
score = other.score
|
||||||
status = other.status
|
status = other.status
|
||||||
started_reading_date = other.started_reading_date
|
started_reading_date = other.started_reading_date
|
||||||
finished_reading_date = other.finished_reading_date
|
finished_reading_date = other.finished_reading_date
|
||||||
|
if (copyRemotePrivate) private = other.private
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -29,4 +29,6 @@ class TrackImpl : Track {
|
|||||||
override var finished_reading_date: Long = 0
|
override var finished_reading_date: Long = 0
|
||||||
|
|
||||||
override var tracking_url: String = ""
|
override var tracking_url: String = ""
|
||||||
|
|
||||||
|
override var private: Boolean = false
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ abstract class BaseTracker(
|
|||||||
// Application and remote support for reading dates
|
// Application and remote support for reading dates
|
||||||
override val supportsReadingDates: Boolean = false
|
override val supportsReadingDates: Boolean = false
|
||||||
|
|
||||||
|
override val supportsPrivateTracking: Boolean = false
|
||||||
|
|
||||||
// TODO: Store all scores as 10 point in the future maybe?
|
// TODO: Store all scores as 10 point in the future maybe?
|
||||||
override fun get10PointScore(track: DomainTrack): Double {
|
override fun get10PointScore(track: DomainTrack): Double {
|
||||||
return track.score
|
return track.score
|
||||||
@ -120,6 +122,11 @@ abstract class BaseTracker(
|
|||||||
updateRemote(track)
|
updateRemote(track)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun setRemotePrivate(track: Track, private: Boolean) {
|
||||||
|
track.private = private
|
||||||
|
updateRemote(track)
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun updateRemote(track: Track): Unit = withIOContext {
|
private suspend fun updateRemote(track: Track): Unit = withIOContext {
|
||||||
try {
|
try {
|
||||||
update(track)
|
update(track)
|
||||||
|
@ -22,6 +22,8 @@ interface Tracker {
|
|||||||
// Application and remote support for reading dates
|
// Application and remote support for reading dates
|
||||||
val supportsReadingDates: Boolean
|
val supportsReadingDates: Boolean
|
||||||
|
|
||||||
|
val supportsPrivateTracking: Boolean
|
||||||
|
|
||||||
@ColorInt
|
@ColorInt
|
||||||
fun getLogoColor(): Int
|
fun getLogoColor(): Int
|
||||||
|
|
||||||
@ -82,4 +84,6 @@ interface Tracker {
|
|||||||
suspend fun setRemoteStartDate(track: Track, epochMillis: Long)
|
suspend fun setRemoteStartDate(track: Track, epochMillis: Long)
|
||||||
|
|
||||||
suspend fun setRemoteFinishDate(track: Track, epochMillis: Long)
|
suspend fun setRemoteFinishDate(track: Track, epochMillis: Long)
|
||||||
|
|
||||||
|
suspend fun setRemotePrivate(track: Track, private: Boolean)
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
|||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -43,6 +42,8 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker {
|
|||||||
|
|
||||||
override val supportsReadingDates: Boolean = true
|
override val supportsReadingDates: Boolean = true
|
||||||
|
|
||||||
|
override val supportsPrivateTracking: Boolean = true
|
||||||
|
|
||||||
private val scorePreference = trackPreferences.anilistScoreType()
|
private val scorePreference = trackPreferences.anilistScoreType()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -183,7 +184,7 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker {
|
|||||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||||
val remoteTrack = api.findLibManga(track, getUsername().toInt())
|
val remoteTrack = api.findLibManga(track, getUsername().toInt())
|
||||||
return if (remoteTrack != null) {
|
return if (remoteTrack != null) {
|
||||||
track.copyPersonalFrom(remoteTrack)
|
track.copyPersonalFrom(remoteTrack, copyRemotePrivate = false)
|
||||||
track.library_id = remoteTrack.library_id
|
track.library_id = remoteTrack.library_id
|
||||||
|
|
||||||
if (track.status != COMPLETED) {
|
if (track.status != COMPLETED) {
|
||||||
|
@ -42,8 +42,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
suspend fun addLibManga(track: Track): Track {
|
suspend fun addLibManga(track: Track): Track {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
val query = """
|
val query = """
|
||||||
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
|
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}private: Boolean) {
|
||||||
|SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) {
|
|SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status, private: ${'$'}private) {
|
||||||
| id
|
| id
|
||||||
| status
|
| status
|
||||||
|}
|
|}
|
||||||
@ -56,6 +56,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
put("mangaId", track.remote_id)
|
put("mangaId", track.remote_id)
|
||||||
put("progress", track.last_chapter_read.toInt())
|
put("progress", track.last_chapter_read.toInt())
|
||||||
put("status", track.toApiStatus())
|
put("status", track.toApiStatus())
|
||||||
|
put("private", track.private)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with(json) {
|
with(json) {
|
||||||
@ -79,11 +80,11 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
return withIOContext {
|
return withIOContext {
|
||||||
val query = """
|
val query = """
|
||||||
|mutation UpdateManga(
|
|mutation UpdateManga(
|
||||||
|${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus,
|
|${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}private: Boolean,
|
||||||
|${'$'}score: Int, ${'$'}startedAt: FuzzyDateInput, ${'$'}completedAt: FuzzyDateInput
|
|${'$'}score: Int, ${'$'}startedAt: FuzzyDateInput, ${'$'}completedAt: FuzzyDateInput
|
||||||
|) {
|
|) {
|
||||||
|SaveMediaListEntry(
|
|SaveMediaListEntry(
|
||||||
|id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status,
|
|id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, private: ${'$'}private,
|
||||||
|scoreRaw: ${'$'}score, startedAt: ${'$'}startedAt, completedAt: ${'$'}completedAt
|
|scoreRaw: ${'$'}score, startedAt: ${'$'}startedAt, completedAt: ${'$'}completedAt
|
||||||
|) {
|
|) {
|
||||||
|id
|
|id
|
||||||
@ -102,6 +103,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
put("score", track.score.toInt())
|
put("score", track.score.toInt())
|
||||||
put("startedAt", createDate(track.started_reading_date))
|
put("startedAt", createDate(track.started_reading_date))
|
||||||
put("completedAt", createDate(track.finished_reading_date))
|
put("completedAt", createDate(track.finished_reading_date))
|
||||||
|
put("private", track.private)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
||||||
@ -190,6 +192,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
|status
|
|status
|
||||||
|scoreRaw: score(format: POINT_100)
|
|scoreRaw: score(format: POINT_100)
|
||||||
|progress
|
|progress
|
||||||
|
|private
|
||||||
|startedAt {
|
|startedAt {
|
||||||
|year
|
|year
|
||||||
|month
|
|month
|
||||||
|
@ -49,6 +49,7 @@ data class ALUserManga(
|
|||||||
val startDateFuzzy: Long,
|
val startDateFuzzy: Long,
|
||||||
val completedDateFuzzy: Long,
|
val completedDateFuzzy: Long,
|
||||||
val manga: ALManga,
|
val manga: ALManga,
|
||||||
|
val private: Boolean,
|
||||||
) {
|
) {
|
||||||
fun toTrack() = Track.create(TrackerManager.ANILIST).apply {
|
fun toTrack() = Track.create(TrackerManager.ANILIST).apply {
|
||||||
remote_id = manga.remoteId
|
remote_id = manga.remoteId
|
||||||
@ -60,6 +61,7 @@ data class ALUserManga(
|
|||||||
last_chapter_read = chaptersRead.toDouble()
|
last_chapter_read = chaptersRead.toDouble()
|
||||||
library_id = libraryId
|
library_id = libraryId
|
||||||
total_chapters = manga.totalChapters
|
total_chapters = manga.totalChapters
|
||||||
|
private = this@ALUserManga.private
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toTrackStatus() = when (listStatus) {
|
private fun toTrackStatus() = when (listStatus) {
|
||||||
|
@ -28,6 +28,7 @@ data class ALUserListItem(
|
|||||||
val startedAt: ALFuzzyDate,
|
val startedAt: ALFuzzyDate,
|
||||||
val completedAt: ALFuzzyDate,
|
val completedAt: ALFuzzyDate,
|
||||||
val media: ALSearchItem,
|
val media: ALSearchItem,
|
||||||
|
val private: Boolean,
|
||||||
) {
|
) {
|
||||||
fun toALUserManga(): ALUserManga {
|
fun toALUserManga(): ALUserManga {
|
||||||
return ALUserManga(
|
return ALUserManga(
|
||||||
@ -38,6 +39,7 @@ data class ALUserListItem(
|
|||||||
startDateFuzzy = startedAt.toEpochMilli(),
|
startDateFuzzy = startedAt.toEpochMilli(),
|
||||||
completedDateFuzzy = completedAt.toEpochMilli(),
|
completedDateFuzzy = completedAt.toEpochMilli(),
|
||||||
manga = media.toALManga(),
|
manga = media.toALManga(),
|
||||||
|
private = private,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi") {
|
|||||||
|
|
||||||
private val api by lazy { BangumiApi(id, client, interceptor) }
|
private val api by lazy { BangumiApi(id, client, interceptor) }
|
||||||
|
|
||||||
|
override val supportsPrivateTracking: Boolean = true
|
||||||
|
|
||||||
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||||
|
|
||||||
override fun displayScore(track: DomainTrack): String {
|
override fun displayScore(track: DomainTrack): String {
|
||||||
@ -49,7 +51,7 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi") {
|
|||||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||||
val statusTrack = api.statusLibManga(track, getUsername())
|
val statusTrack = api.statusLibManga(track, getUsername())
|
||||||
return if (statusTrack != null) {
|
return if (statusTrack != null) {
|
||||||
track.copyPersonalFrom(statusTrack)
|
track.copyPersonalFrom(statusTrack, copyRemotePrivate = false)
|
||||||
track.library_id = statusTrack.library_id
|
track.library_id = statusTrack.library_id
|
||||||
track.score = statusTrack.score
|
track.score = statusTrack.score
|
||||||
track.last_chapter_read = statusTrack.last_chapter_read
|
track.last_chapter_read = statusTrack.last_chapter_read
|
||||||
|
@ -45,6 +45,7 @@ class BangumiApi(
|
|||||||
put("type", track.toApiStatus())
|
put("type", track.toApiStatus())
|
||||||
put("rate", track.score.toInt().coerceIn(0, 10))
|
put("rate", track.score.toInt().coerceIn(0, 10))
|
||||||
put("ep_status", track.last_chapter_read.toInt())
|
put("ep_status", track.last_chapter_read.toInt())
|
||||||
|
put("private", track.private)
|
||||||
}
|
}
|
||||||
.toString()
|
.toString()
|
||||||
.toRequestBody()
|
.toRequestBody()
|
||||||
@ -62,6 +63,7 @@ class BangumiApi(
|
|||||||
put("type", track.toApiStatus())
|
put("type", track.toApiStatus())
|
||||||
put("rate", track.score.toInt().coerceIn(0, 10))
|
put("rate", track.score.toInt().coerceIn(0, 10))
|
||||||
put("ep_status", track.last_chapter_read.toInt())
|
put("ep_status", track.last_chapter_read.toInt())
|
||||||
|
put("private", track.private)
|
||||||
}
|
}
|
||||||
.toString()
|
.toString()
|
||||||
.toRequestBody()
|
.toRequestBody()
|
||||||
|
@ -30,6 +30,8 @@ class TrackSearch : Track {
|
|||||||
|
|
||||||
override var finished_reading_date: Long = 0
|
override var finished_reading_date: Long = 0
|
||||||
|
|
||||||
|
override var private: Boolean = false
|
||||||
|
|
||||||
override lateinit var tracking_url: String
|
override lateinit var tracking_url: String
|
||||||
|
|
||||||
var cover_url: String = ""
|
var cover_url: String = ""
|
||||||
|
@ -172,6 +172,7 @@ data class TrackInfoDialogHomeScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
onCopyLink = { context.copyTrackerLink(it) },
|
onCopyLink = { context.copyTrackerLink(it) },
|
||||||
|
onTogglePrivate = screenModel::togglePrivate,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +248,12 @@ data class TrackInfoDialogHomeScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun togglePrivate(item: TrackItem) {
|
||||||
|
screenModelScope.launchNonCancellable {
|
||||||
|
item.tracker.setRemotePrivate(item.track!!.toDbTrack(), !item.track.private)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun List<Track>.mapToTrackItem(): List<TrackItem> {
|
private fun List<Track>.mapToTrackItem(): List<TrackItem> {
|
||||||
val loggedInTrackers = Injekt.get<TrackerManager>().loggedInTrackers()
|
val loggedInTrackers = Injekt.get<TrackerManager>().loggedInTrackers()
|
||||||
val source = Injekt.get<SourceManager>().getOrStub(sourceId)
|
val source = Injekt.get<SourceManager>().getOrStub(sourceId)
|
||||||
@ -673,11 +680,14 @@ data class TrackerSearchScreen(
|
|||||||
queryResult = state.queryResult,
|
queryResult = state.queryResult,
|
||||||
selected = state.selected,
|
selected = state.selected,
|
||||||
onSelectedChange = screenModel::updateSelection,
|
onSelectedChange = screenModel::updateSelection,
|
||||||
onConfirmSelection = {
|
onConfirmSelection = f@{ private: Boolean ->
|
||||||
screenModel.registerTracking(state.selected!!)
|
val selected = state.selected ?: return@f
|
||||||
|
selected.private = private
|
||||||
|
screenModel.registerTracking(selected)
|
||||||
navigator.pop()
|
navigator.pop()
|
||||||
},
|
},
|
||||||
onDismissRequest = navigator::pop,
|
onDismissRequest = navigator::pop,
|
||||||
|
supportsPrivateTracking = screenModel.supportsPrivateTracking,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -688,6 +698,8 @@ data class TrackerSearchScreen(
|
|||||||
private val tracker: Tracker,
|
private val tracker: Tracker,
|
||||||
) : StateScreenModel<Model.State>(State()) {
|
) : StateScreenModel<Model.State>(State()) {
|
||||||
|
|
||||||
|
val supportsPrivateTracking = tracker.supportsPrivateTracking
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Run search on first launch
|
// Run search on first launch
|
||||||
if (initialQuery.isNotBlank()) {
|
if (initialQuery.isNotBlank()) {
|
||||||
|
@ -17,6 +17,7 @@ data class DummyTracker(
|
|||||||
override val id: Long,
|
override val id: Long,
|
||||||
override val name: String,
|
override val name: String,
|
||||||
override val supportsReadingDates: Boolean = false,
|
override val supportsReadingDates: Boolean = false,
|
||||||
|
override val supportsPrivateTracking: Boolean = false,
|
||||||
override val isLoggedIn: Boolean = false,
|
override val isLoggedIn: Boolean = false,
|
||||||
override val isLoggedInFlow: Flow<Boolean> = flowOf(false),
|
override val isLoggedInFlow: Flow<Boolean> = flowOf(false),
|
||||||
val valLogoColor: Int = Color.rgb(18, 25, 35),
|
val valLogoColor: Int = Color.rgb(18, 25, 35),
|
||||||
@ -119,4 +120,9 @@ data class DummyTracker(
|
|||||||
track: eu.kanade.tachiyomi.data.database.models.Track,
|
track: eu.kanade.tachiyomi.data.database.models.Track,
|
||||||
epochMillis: Long,
|
epochMillis: Long,
|
||||||
) = Unit
|
) = Unit
|
||||||
|
|
||||||
|
override suspend fun setRemotePrivate(
|
||||||
|
track: eu.kanade.tachiyomi.data.database.models.Track,
|
||||||
|
private: Boolean,
|
||||||
|
) = Unit
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ object TrackMapper {
|
|||||||
remoteUrl: String,
|
remoteUrl: String,
|
||||||
startDate: Long,
|
startDate: Long,
|
||||||
finishDate: Long,
|
finishDate: Long,
|
||||||
|
private: Boolean,
|
||||||
): Track = Track(
|
): Track = Track(
|
||||||
id = id,
|
id = id,
|
||||||
mangaId = mangaId,
|
mangaId = mangaId,
|
||||||
@ -31,5 +32,6 @@ object TrackMapper {
|
|||||||
remoteUrl = remoteUrl,
|
remoteUrl = remoteUrl,
|
||||||
startDate = startDate,
|
startDate = startDate,
|
||||||
finishDate = finishDate,
|
finishDate = finishDate,
|
||||||
|
private = private,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,7 @@ class TrackRepositoryImpl(
|
|||||||
remoteUrl = mangaTrack.remoteUrl,
|
remoteUrl = mangaTrack.remoteUrl,
|
||||||
startDate = mangaTrack.startDate,
|
startDate = mangaTrack.startDate,
|
||||||
finishDate = mangaTrack.finishDate,
|
finishDate = mangaTrack.finishDate,
|
||||||
|
private = mangaTrack.private,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import kotlin.Boolean;
|
||||||
|
|
||||||
CREATE TABLE manga_sync(
|
CREATE TABLE manga_sync(
|
||||||
_id INTEGER NOT NULL PRIMARY KEY,
|
_id INTEGER NOT NULL PRIMARY KEY,
|
||||||
manga_id INTEGER NOT NULL,
|
manga_id INTEGER NOT NULL,
|
||||||
@ -12,6 +14,7 @@ CREATE TABLE manga_sync(
|
|||||||
remote_url TEXT NOT NULL,
|
remote_url TEXT NOT NULL,
|
||||||
start_date INTEGER NOT NULL,
|
start_date INTEGER NOT NULL,
|
||||||
finish_date INTEGER NOT NULL,
|
finish_date INTEGER NOT NULL,
|
||||||
|
private INTEGER AS Boolean DEFAULT 0 NOT NULL,
|
||||||
UNIQUE (manga_id, sync_id) ON CONFLICT REPLACE,
|
UNIQUE (manga_id, sync_id) ON CONFLICT REPLACE,
|
||||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||||
ON DELETE CASCADE
|
ON DELETE CASCADE
|
||||||
@ -36,8 +39,8 @@ FROM manga_sync
|
|||||||
WHERE manga_id = :mangaId;
|
WHERE manga_id = :mangaId;
|
||||||
|
|
||||||
insert:
|
insert:
|
||||||
INSERT INTO manga_sync(manga_id,sync_id,remote_id,library_id,title,last_chapter_read,total_chapters,status,score,remote_url,start_date,finish_date)
|
INSERT INTO manga_sync(manga_id,sync_id,remote_id,library_id,title,last_chapter_read,total_chapters,status,score,remote_url,start_date,finish_date,private)
|
||||||
VALUES (:mangaId,:syncId,:remoteId,:libraryId,:title,:lastChapterRead,:totalChapters,:status,:score,:remoteUrl,:startDate,:finishDate);
|
VALUES (:mangaId,:syncId,:remoteId,:libraryId,:title,:lastChapterRead,:totalChapters,:status,:score,:remoteUrl,:startDate,:finishDate,:private);
|
||||||
|
|
||||||
update:
|
update:
|
||||||
UPDATE manga_sync
|
UPDATE manga_sync
|
||||||
@ -53,5 +56,6 @@ SET
|
|||||||
score = coalesce(:score, score),
|
score = coalesce(:score, score),
|
||||||
remote_url = coalesce(:trackingUrl, remote_url),
|
remote_url = coalesce(:trackingUrl, remote_url),
|
||||||
start_date = coalesce(:startDate, start_date),
|
start_date = coalesce(:startDate, start_date),
|
||||||
finish_date = coalesce(:finishDate, finish_date)
|
finish_date = coalesce(:finishDate, finish_date),
|
||||||
|
private = coalesce(:private, private)
|
||||||
WHERE _id = :id;
|
WHERE _id = :id;
|
||||||
|
4
data/src/main/sqldelight/tachiyomi/migrations/4.sqm
Normal file
4
data/src/main/sqldelight/tachiyomi/migrations/4.sqm
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import kotlin.Boolean;
|
||||||
|
|
||||||
|
-- Add private field for tracking
|
||||||
|
ALTER TABLE manga_sync ADD COLUMN private INTEGER AS Boolean DEFAULT 0 NOT NULL;
|
@ -16,4 +16,5 @@ data class Track(
|
|||||||
val remoteUrl: String,
|
val remoteUrl: String,
|
||||||
val startDate: Long,
|
val startDate: Long,
|
||||||
val finishDate: Long,
|
val finishDate: Long,
|
||||||
|
val private: Boolean,
|
||||||
) : Serializable
|
) : Serializable
|
||||||
|
@ -521,7 +521,6 @@
|
|||||||
<string name="enhanced_services">Enhanced trackers</string>
|
<string name="enhanced_services">Enhanced trackers</string>
|
||||||
<string name="enhanced_services_not_installed">Available but source not installed: %s</string>
|
<string name="enhanced_services_not_installed">Available but source not installed: %s</string>
|
||||||
<string name="enhanced_tracking_info">Provides enhanced features for specific sources. Entries are automatically tracked when added to your library.</string>
|
<string name="enhanced_tracking_info">Provides enhanced features for specific sources. Entries are automatically tracked when added to your library.</string>
|
||||||
<string name="action_track">Track</string>
|
|
||||||
<string name="track_activity_name">Tracker login</string>
|
<string name="track_activity_name">Tracker login</string>
|
||||||
|
|
||||||
<!-- Browse section -->
|
<!-- Browse section -->
|
||||||
@ -752,6 +751,7 @@
|
|||||||
<!-- Tracking Screen -->
|
<!-- Tracking Screen -->
|
||||||
<string name="manga_tracking_tab">Tracking</string>
|
<string name="manga_tracking_tab">Tracking</string>
|
||||||
<string name="add_tracking">Add tracking</string>
|
<string name="add_tracking">Add tracking</string>
|
||||||
|
<string name="action_track">Track</string>
|
||||||
<string name="unread">Unread</string>
|
<string name="unread">Unread</string>
|
||||||
<string name="reading">Reading</string>
|
<string name="reading">Reading</string>
|
||||||
<string name="completed">Completed</string>
|
<string name="completed">Completed</string>
|
||||||
@ -771,6 +771,9 @@
|
|||||||
<string name="track_status">Status</string>
|
<string name="track_status">Status</string>
|
||||||
<string name="track_started_reading_date">Start date</string>
|
<string name="track_started_reading_date">Start date</string>
|
||||||
<string name="track_finished_reading_date">Finish date</string>
|
<string name="track_finished_reading_date">Finish date</string>
|
||||||
|
<string name="tracked_privately">Tracked privately</string>
|
||||||
|
<string name="action_toggle_private_on">Track privately</string>
|
||||||
|
<string name="action_toggle_private_off">Track publicly</string>
|
||||||
<string name="track_type">Type</string>
|
<string name="track_type">Type</string>
|
||||||
<string name="myanimelist_relogin">Please login to MAL again</string>
|
<string name="myanimelist_relogin">Please login to MAL again</string>
|
||||||
<string name="source_unsupported">Source is not supported</string>
|
<string name="source_unsupported">Source is not supported</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user