Misc cleanup
- Rebased against master - Removed unnecessary tabs for now
This commit is contained in:
parent
255ed50685
commit
14eb114ee8
18 changed files with 478 additions and 2 deletions
|
@ -22,7 +22,7 @@ android {
|
|||
defaultConfig {
|
||||
applicationId = "eu.kanade.tachiyomi"
|
||||
|
||||
versionCode = 109
|
||||
versionCode = 110
|
||||
versionName = "0.14.7"
|
||||
|
||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||
|
|
|
@ -29,6 +29,7 @@ import tachiyomi.data.manga.MangaRepositoryImpl
|
|||
import tachiyomi.data.release.ReleaseServiceImpl
|
||||
import tachiyomi.data.source.SourceRepositoryImpl
|
||||
import tachiyomi.data.source.StubSourceRepositoryImpl
|
||||
import tachiyomi.data.stat.DownloadStatRepositoryImpl
|
||||
import tachiyomi.data.track.TrackRepositoryImpl
|
||||
import tachiyomi.data.updates.UpdatesRepositoryImpl
|
||||
import tachiyomi.domain.category.interactor.CreateCategoryWithName
|
||||
|
@ -72,6 +73,9 @@ import tachiyomi.domain.source.interactor.GetRemoteManga
|
|||
import tachiyomi.domain.source.interactor.GetSourcesWithNonLibraryManga
|
||||
import tachiyomi.domain.source.repository.SourceRepository
|
||||
import tachiyomi.domain.source.repository.StubSourceRepository
|
||||
import tachiyomi.domain.stat.interactor.AddDownloadStatOperation
|
||||
import tachiyomi.domain.stat.interactor.GetDownloadStatOperations
|
||||
import tachiyomi.domain.stat.repository.DownloadStatRepository
|
||||
import tachiyomi.domain.track.interactor.DeleteTrack
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.interactor.GetTracksPerManga
|
||||
|
@ -167,5 +171,9 @@ class DomainModule : InjektModule {
|
|||
addFactory { ToggleLanguage(get()) }
|
||||
addFactory { ToggleSource(get()) }
|
||||
addFactory { ToggleSourcePin(get()) }
|
||||
|
||||
addSingletonFactory<DownloadStatRepository> { DownloadStatRepositoryImpl(get()) }
|
||||
addFactory { GetDownloadStatOperations(get()) }
|
||||
addFactory { AddDownloadStatOperation(get()) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package eu.kanade.presentation.more.download
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.more.download.components.DeletedStatsRow
|
||||
import eu.kanade.presentation.more.download.components.DownloadStatOverviewSection
|
||||
import eu.kanade.presentation.more.download.components.DownloadStatsRow
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
class DownloadStatsScreen : Screen() {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val screenModel = rememberScreenModel { DownloadStatsScreenModel() }
|
||||
val state by screenModel.state.collectAsState()
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
|
||||
Scaffold(
|
||||
topBar = { scrollBehavior ->
|
||||
AppBar(
|
||||
title = stringResource(MR.strings.label_download_stats),
|
||||
navigateUp = navigator::pop,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
) { contentPadding ->
|
||||
when {
|
||||
state.isLoading -> LoadingScreen(Modifier.padding(contentPadding))
|
||||
else -> {
|
||||
OverallStats(
|
||||
state = state,
|
||||
contentPadding = contentPadding,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OverallStats(
|
||||
state: DownloadStatsScreenModel.State,
|
||||
contentPadding: PaddingValues,
|
||||
) {
|
||||
LazyColumn(
|
||||
contentPadding = contentPadding,
|
||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
|
||||
) {
|
||||
item {
|
||||
DownloadStatOverviewSection(state.uniqueItems)
|
||||
}
|
||||
item {
|
||||
DownloadStatsRow(state.downloadStatOperations.filter { it.size > 0 })
|
||||
}
|
||||
item {
|
||||
DeletedStatsRow(state.downloadStatOperations.filter { it.size < 0 })
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package eu.kanade.presentation.more.download
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import eu.kanade.presentation.more.download.data.DownloadStatManga
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.update
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.domain.manga.interactor.GetLibraryManga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.stat.interactor.GetDownloadStatOperations
|
||||
import tachiyomi.domain.stat.model.DownloadStatOperation
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
|
||||
class DownloadStatsScreenModel(
|
||||
private val getLibraryManga: GetLibraryManga = Injekt.get(),
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val downloadManager: DownloadManager = Injekt.get(),
|
||||
private val downloadProvider: DownloadProvider = Injekt.get(),
|
||||
private val getDownloadStatOperations: GetDownloadStatOperations = Injekt.get(),
|
||||
) : StateScreenModel<DownloadStatsScreenModel.State>(State()) {
|
||||
|
||||
init {
|
||||
screenModelScope.launchIO {
|
||||
mutableState.update { state ->
|
||||
state.copy(
|
||||
items = getLibraryManga.await().map { libraryManga ->
|
||||
val source = sourceManager.getOrStub(libraryManga.manga.source)
|
||||
val path = downloadProvider.findMangaDir(
|
||||
libraryManga.manga.title,
|
||||
source,
|
||||
)?.filePath
|
||||
DownloadStatManga(
|
||||
libraryManga = libraryManga,
|
||||
folderSize = if (path != null) DiskUtil.getDirectorySize(File(path)) else 0,
|
||||
downloadChaptersCount = downloadManager.getDownloadCount(libraryManga.manga),
|
||||
)
|
||||
},
|
||||
downloadStatOperations = getDownloadStatOperations.await(),
|
||||
isLoading = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
screenModelScope.launchIO {
|
||||
getDownloadStatOperations.subscribe()
|
||||
.distinctUntilChanged()
|
||||
.collectLatest { operations ->
|
||||
mutableState.update { state ->
|
||||
val oldOperationsId = state.downloadStatOperations.map { it.id }.toHashSet()
|
||||
val newOperations = operations
|
||||
.mapNotNull { if (!oldOperationsId.contains(it.id)) it else null }
|
||||
.groupBy { it.mangaId }
|
||||
val newItems = state.items.map { item ->
|
||||
if (newOperations.containsKey(item.libraryManga.id)) {
|
||||
item.copy(
|
||||
folderSize = item.folderSize +
|
||||
newOperations[item.libraryManga.id]!!
|
||||
.sumOf { it.size },
|
||||
downloadChaptersCount = item.downloadChaptersCount +
|
||||
newOperations[item.libraryManga.id]!!.sumOf { it.units }.toInt(),
|
||||
)
|
||||
} else {
|
||||
item
|
||||
}
|
||||
}
|
||||
state.copy(
|
||||
items = newItems,
|
||||
downloadStatOperations = operations,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val isLoading: Boolean = true,
|
||||
val items: List<DownloadStatManga> = emptyList(),
|
||||
val downloadStatOperations: List<DownloadStatOperation> = emptyList(),
|
||||
) {
|
||||
|
||||
val uniqueItems: List<DownloadStatManga> by lazy {
|
||||
val uniqueIds = HashSet<Long>()
|
||||
val uniqueMangas = mutableListOf<DownloadStatManga>()
|
||||
for (manga in items) {
|
||||
if (uniqueIds.add(manga.libraryManga.manga.id)) {
|
||||
uniqueMangas.add(manga)
|
||||
}
|
||||
}
|
||||
uniqueMangas
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package eu.kanade.presentation.more.download.components
|
||||
|
||||
import android.text.format.Formatter
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Book
|
||||
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
||||
import androidx.compose.material.icons.outlined.Storage
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import eu.kanade.presentation.more.download.data.DownloadStatManga
|
||||
import eu.kanade.presentation.more.stats.components.StatsItem
|
||||
import eu.kanade.presentation.more.stats.components.StatsOverviewItem
|
||||
import eu.kanade.presentation.more.stats.components.StatsSection
|
||||
import tachiyomi.domain.stat.model.DownloadStatOperation
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import kotlin.math.abs
|
||||
|
||||
@Composable
|
||||
fun DownloadStatOverviewSection(
|
||||
items: List<DownloadStatManga>,
|
||||
) {
|
||||
StatsSection(MR.strings.label_overview_section) {
|
||||
Row {
|
||||
StatsOverviewItem(
|
||||
title = folderSizeText(items.sumOf { it.folderSize }),
|
||||
subtitle = stringResource(MR.strings.label_size),
|
||||
icon = Icons.Outlined.Storage,
|
||||
)
|
||||
StatsOverviewItem(
|
||||
title = items.sumOf { it.downloadChaptersCount }.toString(),
|
||||
subtitle = stringResource(MR.strings.chapters),
|
||||
icon = Icons.Outlined.Book,
|
||||
)
|
||||
StatsOverviewItem(
|
||||
title = items.filter { it.downloadChaptersCount > 0 }.size.toString(),
|
||||
subtitle = stringResource(MR.strings.manga),
|
||||
icon = Icons.Outlined.CollectionsBookmark,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DownloadStatsRow(
|
||||
data: List<DownloadStatOperation>,
|
||||
) {
|
||||
StatsSection(MR.strings.downloaded_chapters) {
|
||||
Row {
|
||||
StatsItem(
|
||||
data.size.toString(),
|
||||
stringResource(MR.strings.label_total_chapters),
|
||||
)
|
||||
StatsItem(
|
||||
folderSizeText(data.sumOf { abs(it.size) }),
|
||||
stringResource(MR.strings.label_size),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DeletedStatsRow(
|
||||
data: List<DownloadStatOperation>,
|
||||
) {
|
||||
StatsSection(MR.strings.deleted_chapters) {
|
||||
Row {
|
||||
StatsItem(
|
||||
abs(data.sumOf { it.units }).toString(),
|
||||
stringResource(MR.strings.label_total_chapters),
|
||||
)
|
||||
StatsItem(
|
||||
folderSizeText(abs(data.sumOf { it.size })),
|
||||
stringResource(MR.strings.label_size),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun folderSizeText(folderSize: Long): String {
|
||||
val context = LocalContext.current
|
||||
return Formatter.formatFileSize(context, folderSize)
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package eu.kanade.presentation.more.download.data
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import tachiyomi.domain.library.model.LibraryManga
|
||||
|
||||
@Immutable
|
||||
data class DownloadStatManga(
|
||||
val libraryManga: LibraryManga,
|
||||
val folderSize: Long = 0,
|
||||
val downloadChaptersCount: Int = 0,
|
||||
)
|
|
@ -28,6 +28,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.more.download.DownloadStatsScreen
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.presentation.more.settings.screen.data.CreateBackupScreen
|
||||
import eu.kanade.presentation.more.settings.widget.BasePreferenceWidget
|
||||
|
@ -255,6 +256,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||
val scope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
|
||||
val chapterCache = remember { Injekt.get<ChapterCache>() }
|
||||
var cacheReadableSizeSema by remember { mutableIntStateOf(0) }
|
||||
|
@ -287,6 +289,10 @@ object SettingsDataScreen : SearchableSettings {
|
|||
pref = libraryPreferences.autoClearChapterCache(),
|
||||
title = stringResource(MR.strings.pref_auto_clear_chapter_cache),
|
||||
),
|
||||
Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(MR.strings.label_download_stats),
|
||||
onClick = { navigator.push(DownloadStatsScreen()) },
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.drop
|
||||
|
@ -22,9 +23,12 @@ import tachiyomi.domain.chapter.model.Chapter
|
|||
import tachiyomi.domain.download.service.DownloadPreferences
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.stat.interactor.AddDownloadStatOperation
|
||||
import tachiyomi.domain.stat.model.DownloadStatOperation
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* This class is used to manage chapter downloads in the application. It must be instantiated once
|
||||
|
@ -38,6 +42,7 @@ class DownloadManager(
|
|||
private val getCategories: GetCategories = Injekt.get(),
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
||||
private val addDownloadStatOperation: AddDownloadStatOperation = Injekt.get(),
|
||||
) {
|
||||
|
||||
/**
|
||||
|
@ -224,6 +229,13 @@ class DownloadManager(
|
|||
removeFromDownloadQueue(filteredChapters)
|
||||
|
||||
val (mangaDir, chapterDirs) = provider.findChapterDirs(filteredChapters, manga, source)
|
||||
addDownloadStatOperation.await(
|
||||
DownloadStatOperation.create().copy(
|
||||
mangaId = manga.id,
|
||||
size = chapterDirs.sumOf { DiskUtil.getDirectorySize(File(it.filePath!!)) } * -1,
|
||||
units = filteredChapters.size.toLong() * -1,
|
||||
),
|
||||
)
|
||||
chapterDirs.forEach { it.delete() }
|
||||
cache.removeChapters(filteredChapters, manga)
|
||||
|
||||
|
@ -246,7 +258,18 @@ class DownloadManager(
|
|||
if (removeQueued) {
|
||||
downloader.removeFromQueue(manga)
|
||||
}
|
||||
provider.findMangaDir(manga.title, source)?.delete()
|
||||
val mangaDir = provider.findMangaDir(manga.title, source)
|
||||
val dirSize = DiskUtil.getDirectorySize(File(mangaDir?.filePath!!))
|
||||
if (dirSize > 0) {
|
||||
addDownloadStatOperation.await(
|
||||
DownloadStatOperation.create().copy(
|
||||
mangaId = manga.id,
|
||||
size = dirSize * -1,
|
||||
units = cache.getDownloadCount(manga).toLong() * -1,
|
||||
),
|
||||
)
|
||||
}
|
||||
mangaDir.delete()
|
||||
cache.removeManga(manga)
|
||||
|
||||
// Delete source directory if empty
|
||||
|
|
|
@ -54,6 +54,8 @@ import tachiyomi.domain.chapter.model.Chapter
|
|||
import tachiyomi.domain.download.service.DownloadPreferences
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.stat.interactor.AddDownloadStatOperation
|
||||
import tachiyomi.domain.stat.model.DownloadStatOperation
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
@ -75,6 +77,7 @@ class Downloader(
|
|||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val chapterCache: ChapterCache = Injekt.get(),
|
||||
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
||||
private val addDownloadStatOperation: AddDownloadStatOperation = Injekt.get(),
|
||||
private val xml: XML = Injekt.get(),
|
||||
private val getCategories: GetCategories = Injekt.get(),
|
||||
) {
|
||||
|
@ -406,6 +409,22 @@ class Downloader(
|
|||
|
||||
DiskUtil.createNoMediaFile(tmpDir, context)
|
||||
|
||||
addDownloadStatOperation.await(
|
||||
DownloadStatOperation.create().copy(
|
||||
mangaId = download.manga.id,
|
||||
size = DiskUtil.getDirectorySize(
|
||||
File(
|
||||
provider.findChapterDir(
|
||||
download.chapter.name,
|
||||
download.chapter.scanlator,
|
||||
download.manga.title,
|
||||
download.source,
|
||||
)?.filePath!!,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
download.status = Download.State.DOWNLOADED
|
||||
} catch (error: Throwable) {
|
||||
if (error is CancellationException) throw error
|
||||
|
|
19
data/src/main/java/tachiyomi/data/stat/DownloadStatMapper.kt
Normal file
19
data/src/main/java/tachiyomi/data/stat/DownloadStatMapper.kt
Normal file
|
@ -0,0 +1,19 @@
|
|||
package tachiyomi.data.stat
|
||||
|
||||
import tachiyomi.domain.stat.model.DownloadStatOperation
|
||||
|
||||
object DownloadStatMapper {
|
||||
fun map(
|
||||
id: Long,
|
||||
mangaId: Long?,
|
||||
date: Long,
|
||||
size: Long,
|
||||
units: Long,
|
||||
): DownloadStatOperation = DownloadStatOperation(
|
||||
id = id,
|
||||
mangaId = mangaId,
|
||||
date = date * 1000,
|
||||
size = size,
|
||||
units = units,
|
||||
)
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package tachiyomi.data.stat
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.data.DatabaseHandler
|
||||
import tachiyomi.domain.stat.model.DownloadStatOperation
|
||||
import tachiyomi.domain.stat.repository.DownloadStatRepository
|
||||
|
||||
class DownloadStatRepositoryImpl(
|
||||
private val handler: DatabaseHandler,
|
||||
) : DownloadStatRepository {
|
||||
|
||||
override suspend fun getStatOperations(): List<DownloadStatOperation> {
|
||||
return handler.awaitList { download_statQueries.getStatOperations(DownloadStatMapper::map) }
|
||||
}
|
||||
|
||||
override suspend fun getStatOperationsAsFlow(): Flow<List<DownloadStatOperation>> {
|
||||
return handler.subscribeToList { download_statQueries.getStatOperations(DownloadStatMapper::map) }
|
||||
}
|
||||
|
||||
override suspend fun insert(operation: DownloadStatOperation) {
|
||||
handler.await {
|
||||
download_statQueries.insert(
|
||||
mangaId = operation.mangaId,
|
||||
date = operation.date / 1000,
|
||||
size = operation.size,
|
||||
units = operation.units,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
18
data/src/main/sqldelight/tachiyomi/data/download_stat.sq
Normal file
18
data/src/main/sqldelight/tachiyomi/data/download_stat.sq
Normal file
|
@ -0,0 +1,18 @@
|
|||
CREATE TABLE download_stat(
|
||||
_id INTEGER NOT NULL PRIMARY KEY,
|
||||
manga_id INTEGER,
|
||||
date INTEGER NOT NULL DEFAULT 0,
|
||||
size INTEGER NOT NULL,
|
||||
units INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||
ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- Methods
|
||||
getStatOperations:
|
||||
SELECT * FROM download_stat;
|
||||
|
||||
insert:
|
||||
INSERT INTO download_stat(manga_id, date, size, units)
|
||||
VALUES (:mangaId, :date, :size, :units);
|
10
data/src/main/sqldelight/tachiyomi/migrations/28.sqm
Normal file
10
data/src/main/sqldelight/tachiyomi/migrations/28.sqm
Normal file
|
@ -0,0 +1,10 @@
|
|||
CREATE TABLE download_stat(
|
||||
_id INTEGER NOT NULL PRIMARY KEY,
|
||||
manga_id INTEGER,
|
||||
date INTEGER NOT NULL DEFAULT 0,
|
||||
size INTEGER NOT NULL,
|
||||
units INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||
ON DELETE SET NULL
|
||||
);
|
|
@ -0,0 +1,13 @@
|
|||
package tachiyomi.domain.stat.interactor
|
||||
|
||||
import tachiyomi.domain.stat.model.DownloadStatOperation
|
||||
import tachiyomi.domain.stat.repository.DownloadStatRepository
|
||||
|
||||
class AddDownloadStatOperation(
|
||||
private val repository: DownloadStatRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(actions: DownloadStatOperation) {
|
||||
repository.insert(actions)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package tachiyomi.domain.stat.interactor
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.domain.stat.model.DownloadStatOperation
|
||||
import tachiyomi.domain.stat.repository.DownloadStatRepository
|
||||
|
||||
class GetDownloadStatOperations(
|
||||
private val repository: DownloadStatRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(): List<DownloadStatOperation> {
|
||||
return repository.getStatOperations()
|
||||
}
|
||||
|
||||
suspend fun subscribe(): Flow<List<DownloadStatOperation>> {
|
||||
return repository.getStatOperationsAsFlow()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package tachiyomi.domain.stat.model
|
||||
|
||||
import java.util.Date
|
||||
|
||||
data class DownloadStatOperation(
|
||||
val id: Long,
|
||||
val mangaId: Long?,
|
||||
val date: Long,
|
||||
val size: Long,
|
||||
val units: Long,
|
||||
) {
|
||||
companion object {
|
||||
fun create() = DownloadStatOperation(
|
||||
id = -1,
|
||||
mangaId = -1,
|
||||
date = Date().time,
|
||||
size = -1,
|
||||
units = 1,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package tachiyomi.domain.stat.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.domain.stat.model.DownloadStatOperation
|
||||
|
||||
interface DownloadStatRepository {
|
||||
|
||||
suspend fun getStatOperations(): List<DownloadStatOperation>
|
||||
|
||||
suspend fun getStatOperationsAsFlow(): Flow<List<DownloadStatOperation>>
|
||||
|
||||
suspend fun insert(operation: DownloadStatOperation)
|
||||
}
|
|
@ -31,6 +31,7 @@
|
|||
<string name="label_backup">Backup and restore</string>
|
||||
<string name="label_data_storage">Data and storage</string>
|
||||
<string name="label_stats">Statistics</string>
|
||||
<string name="label_download_stats">Download statistics</string>
|
||||
<string name="label_migration">Migrate</string>
|
||||
<string name="label_extensions">Extensions</string>
|
||||
<string name="label_extension_info">Extension info</string>
|
||||
|
@ -166,6 +167,11 @@
|
|||
<string name="action_faq_and_guides">FAQ and Guides</string>
|
||||
<string name="action_not_now">Not now</string>
|
||||
|
||||
<!-- downloads stats screen -->
|
||||
<string name="label_download_stats_overall_tab">Overall</string>
|
||||
<string name="label_size">Size</string>
|
||||
<string name="deleted_chapters">Deleted chapters</string>
|
||||
|
||||
<!-- Operations -->
|
||||
<string name="loading">Loading…</string>
|
||||
<string name="internal_error">InternalError: Check crash logs for further information</string>
|
||||
|
|
Reference in a new issue