Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0153e90bf0 | ||
|
|
d4f8fe83f5 | ||
|
|
d28b1e4094 | ||
|
|
cd2de0136a |
114
.github/workflows/auto_release.yml
vendored
Normal file
114
.github/workflows/auto_release.yml
vendored
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
name: Build automatic release
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
outputs:
|
||||||
|
should_build: ${{ steps.check-updates.outputs.has_changes }}
|
||||||
|
steps:
|
||||||
|
- name: Check for updates 🌏
|
||||||
|
id: check-updates
|
||||||
|
run: |
|
||||||
|
last_run=$(curl -s "https://api.github.com/repos/${{ github.repository }}/releases/latest" | jq -r '.created_at')
|
||||||
|
kotatsu_updated=$(curl -s "https://api.github.com/repos/KotatsuApp/Kotatsu/commits?since=$last_run" | jq '. | length')
|
||||||
|
parsers_updated=$(curl -s "https://api.github.com/repos/KotatsuApp/kotatsu-parsers/commits?since=$last_run" | jq '. | length')
|
||||||
|
if [ "$kotatsu_updated" -gt "0" ] || [ "$parsers_updated" -gt "0" ]; then
|
||||||
|
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
build:
|
||||||
|
needs: check
|
||||||
|
if: needs.check.outputs.should_build == 'true'
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
outputs:
|
||||||
|
new_tag: ${{ steps.tagger.outputs.new_tag }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: autobuild
|
||||||
|
|
||||||
|
- uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: '17'
|
||||||
|
cache: 'gradle'
|
||||||
|
|
||||||
|
- name: Setup Android SDK 💻
|
||||||
|
uses: android-actions/setup-android@v3
|
||||||
|
|
||||||
|
- name: Grant permissions 💻
|
||||||
|
run: chmod a+x gradlew
|
||||||
|
|
||||||
|
- name: Generate build number 📆
|
||||||
|
id: tagger
|
||||||
|
run: |
|
||||||
|
echo "new_tag=$(./gradlew -q versionInfo -DbuildNumberIncrement=true)" >> $GITHUB_OUTPUT
|
||||||
|
echo "formatted_date=$(date +'%Y/%m/%d')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Decode Keystore
|
||||||
|
id: decode_keystore
|
||||||
|
uses: timheuer/base64-to-file@v1
|
||||||
|
with:
|
||||||
|
fileName: 'keystore/kotatsu.jks'
|
||||||
|
encodedString: ${{ secrets.ANDROID_SIGNING_KEY }}
|
||||||
|
|
||||||
|
- name: Building new APK 💻
|
||||||
|
run: >-
|
||||||
|
./gradlew assembleRelease
|
||||||
|
-DparsersVersionOverride=$(curl -s https://api.github.com/repos/kotatsuapp/kotatsu-parsers/commits/master -H "Accept: application/vnd.github.sha" | cut -c -10)
|
||||||
|
|
||||||
|
- name: Prepare to Upload 🌏
|
||||||
|
run: |
|
||||||
|
mv ${{steps.sign_app.outputs.signedFile}} app/build/outputs/apk/release/release.apk
|
||||||
|
echo "SIGNED_APK=app/build/outputs/apk/release/release.apk" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Get latest changes 📑
|
||||||
|
id: changelog
|
||||||
|
run: |
|
||||||
|
CHANGELOG=$(cat CHANGELOG.txt)
|
||||||
|
echo "content<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "$CHANGELOG" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Create new GH Release + Uploading 🌏
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: v${{ steps.tagger.outputs.new_tag }}
|
||||||
|
name: "Build ${{ steps.tagger.outputs.new_tag }}"
|
||||||
|
body: |
|
||||||
|
Automated build generated on ${{ steps.tagger.outputs.formatted_date }}
|
||||||
|
|
||||||
|
${{ steps.changelog.outputs.content }}
|
||||||
|
files: ${{ env.SIGNED_APK }}
|
||||||
|
prerelease: false
|
||||||
|
|
||||||
|
update:
|
||||||
|
needs: build
|
||||||
|
if: needs.check.outputs.should_build == 'true'
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: autobuild
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Commit 🌏
|
||||||
|
run: |
|
||||||
|
git config --local user.email "autorelease@users.noreply.github.com"
|
||||||
|
git config --local user.name "autorelease"
|
||||||
|
if [[ -n $(git status -s) ]]; then
|
||||||
|
git add README.md
|
||||||
|
git commit -m "Automatic release v${{ needs.build.outputs.new_tag }}"
|
||||||
|
git push origin autobuild
|
||||||
|
else
|
||||||
|
echo "No changes to push!"
|
||||||
|
fi
|
||||||
@@ -9,17 +9,24 @@ plugins {
|
|||||||
id 'dagger.hilt.android.plugin'
|
id 'dagger.hilt.android.plugin'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def Properties versionProps = getVersionProps()
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk = 35
|
compileSdk = 35
|
||||||
buildToolsVersion = '35.0.0'
|
buildToolsVersion = '35.0.0'
|
||||||
namespace = 'org.koitharu.kotatsu'
|
namespace = 'org.koitharu.kotatsu'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
def code = versionProps['code'].toInteger()
|
||||||
|
def base = versionProps['base'].trim()
|
||||||
|
def build = versionProps['build'].toInteger()
|
||||||
|
def variant = versionProps['variant'].trim()
|
||||||
|
|
||||||
applicationId 'org.koitharu.kotatsu'
|
applicationId 'org.koitharu.kotatsu'
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 703
|
versionCode = code * 1000 + build
|
||||||
versionName = '7.7.11'
|
versionName = base + (build == 0 ? '' : '.' + build) + (variant == '' ? '' : '-') + variant
|
||||||
generatedDensities = []
|
generatedDensities = []
|
||||||
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
|
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
|
||||||
ksp {
|
ksp {
|
||||||
@@ -30,6 +37,22 @@ android {
|
|||||||
generateLocaleConfig true
|
generateLocaleConfig true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
signingConfigs {
|
||||||
|
release {
|
||||||
|
def tmpFilePath = System.getProperty("user.home") + "/work/_temp/keystore/"
|
||||||
|
def allFilesFromDir = new File(tmpFilePath).listFiles()
|
||||||
|
|
||||||
|
if (allFilesFromDir != null) {
|
||||||
|
def keystoreFile = allFilesFromDir.first()
|
||||||
|
keystoreFile.renameTo("keystore/kotatsu.jks")
|
||||||
|
}
|
||||||
|
|
||||||
|
storeFile = file("keystore/kotatsu.jks")
|
||||||
|
storePassword System.getenv("SIGNING_STORE_PASSWORD")
|
||||||
|
keyAlias System.getenv("SIGNING_KEY_ALIAS")
|
||||||
|
keyPassword System.getenv("SIGNING_KEY_PASSWORD")
|
||||||
|
}
|
||||||
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
applicationIdSuffix = '.debug'
|
applicationIdSuffix = '.debug'
|
||||||
@@ -38,6 +61,7 @@ android {
|
|||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
shrinkResources true
|
shrinkResources true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
nightly {
|
nightly {
|
||||||
initWith release
|
initWith release
|
||||||
@@ -194,3 +218,22 @@ dependencies {
|
|||||||
androidTestImplementation libs.hilt.android.testing
|
androidTestImplementation libs.hilt.android.testing
|
||||||
kaptAndroidTest libs.hilt.android.compiler
|
kaptAndroidTest libs.hilt.android.compiler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register('versionInfo') {
|
||||||
|
def base = versionProps['base'].trim()
|
||||||
|
def build = versionProps['build'].toInteger()
|
||||||
|
def variant = versionProps['variant'].trim()
|
||||||
|
println base + (build == 0 ? '' : '.' + build) + (variant == '' ? '' : '-') + variant
|
||||||
|
}
|
||||||
|
|
||||||
|
def getVersionProps() {
|
||||||
|
def versionPropsFile = file('version.properties')
|
||||||
|
def Properties versionProps = new Properties()
|
||||||
|
versionProps.load(new FileInputStream(versionPropsFile))
|
||||||
|
if (System.getProperty('buildNumberIncrement') == 'true') {
|
||||||
|
def code = versionProps['build'].toInteger() + 1
|
||||||
|
versionProps['build'] = code.toString()
|
||||||
|
versionProps.store(versionPropsFile.newWriter(), null)
|
||||||
|
}
|
||||||
|
return versionProps
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
|
|||||||
import org.koitharu.kotatsu.list.ui.adapter.ListHeaderClickListener
|
import org.koitharu.kotatsu.list.ui.adapter.ListHeaderClickListener
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
|
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
|
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.errorStateListAD
|
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
|
import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
|
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
|
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
|
||||||
@@ -26,7 +25,6 @@ class BookmarksAdapter(
|
|||||||
init {
|
init {
|
||||||
addDelegate(ListItemType.PAGE_THUMB, bookmarkLargeAD(coil, lifecycleOwner, clickListener))
|
addDelegate(ListItemType.PAGE_THUMB, bookmarkLargeAD(coil, lifecycleOwner, clickListener))
|
||||||
addDelegate(ListItemType.HEADER, listHeaderAD(headerClickListener))
|
addDelegate(ListItemType.HEADER, listHeaderAD(headerClickListener))
|
||||||
addDelegate(ListItemType.STATE_ERROR, errorStateListAD(null))
|
|
||||||
addDelegate(ListItemType.FOOTER_LOADING, loadingFooterAD())
|
addDelegate(ListItemType.FOOTER_LOADING, loadingFooterAD())
|
||||||
addDelegate(ListItemType.STATE_LOADING, loadingStateAD())
|
addDelegate(ListItemType.STATE_LOADING, loadingStateAD())
|
||||||
addDelegate(ListItemType.STATE_EMPTY, emptyStateListAD(coil, lifecycleOwner, null))
|
addDelegate(ListItemType.STATE_EMPTY, emptyStateListAD(coil, lifecycleOwner, null))
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import org.koitharu.kotatsu.core.db.migrations.Migration1To2
|
|||||||
import org.koitharu.kotatsu.core.db.migrations.Migration20To21
|
import org.koitharu.kotatsu.core.db.migrations.Migration20To21
|
||||||
import org.koitharu.kotatsu.core.db.migrations.Migration21To22
|
import org.koitharu.kotatsu.core.db.migrations.Migration21To22
|
||||||
import org.koitharu.kotatsu.core.db.migrations.Migration22To23
|
import org.koitharu.kotatsu.core.db.migrations.Migration22To23
|
||||||
import org.koitharu.kotatsu.core.db.migrations.Migration24To23
|
|
||||||
import org.koitharu.kotatsu.core.db.migrations.Migration2To3
|
import org.koitharu.kotatsu.core.db.migrations.Migration2To3
|
||||||
import org.koitharu.kotatsu.core.db.migrations.Migration3To4
|
import org.koitharu.kotatsu.core.db.migrations.Migration3To4
|
||||||
import org.koitharu.kotatsu.core.db.migrations.Migration4To5
|
import org.koitharu.kotatsu.core.db.migrations.Migration4To5
|
||||||
@@ -129,7 +128,6 @@ fun getDatabaseMigrations(context: Context): Array<Migration> = arrayOf(
|
|||||||
Migration20To21(),
|
Migration20To21(),
|
||||||
Migration21To22(),
|
Migration21To22(),
|
||||||
Migration22To23(),
|
Migration22To23(),
|
||||||
Migration24To23(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun MangaDatabase(context: Context): MangaDatabase = Room
|
fun MangaDatabase(context: Context): MangaDatabase = Room
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.core.db.migrations
|
|
||||||
|
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
|
|
||||||
class Migration24To23 : Migration(24, 23) {
|
|
||||||
|
|
||||||
override fun migrate(db: SupportSQLiteDatabase) {
|
|
||||||
db.execSQL("DROP TABLE IF EXISTS `chapters`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +1,17 @@
|
|||||||
package org.koitharu.kotatsu.core.ui.model
|
package org.koitharu.kotatsu.core.ui.model
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.res.Resources
|
||||||
import android.text.format.DateUtils
|
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.util.ext.toMillis
|
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
sealed class DateTimeAgo {
|
sealed class DateTimeAgo {
|
||||||
|
|
||||||
abstract fun format(context: Context): String
|
abstract fun format(resources: Resources): String
|
||||||
|
|
||||||
object JustNow : DateTimeAgo() {
|
object JustNow : DateTimeAgo() {
|
||||||
override fun format(context: Context): String {
|
override fun format(resources: Resources): String {
|
||||||
return context.getString(R.string.just_now)
|
return resources.getString(R.string.just_now)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "just_now"
|
override fun toString() = "just_now"
|
||||||
@@ -21,32 +20,24 @@ sealed class DateTimeAgo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class MinutesAgo(val minutes: Int) : DateTimeAgo() {
|
data class MinutesAgo(val minutes: Int) : DateTimeAgo() {
|
||||||
override fun format(context: Context): String {
|
override fun format(resources: Resources): String {
|
||||||
return context.resources.getQuantityString(
|
return resources.getQuantityString(R.plurals.minutes_ago, minutes, minutes)
|
||||||
R.plurals.minutes_ago,
|
|
||||||
minutes,
|
|
||||||
minutes,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "minutes_ago_$minutes"
|
override fun toString() = "minutes_ago_$minutes"
|
||||||
}
|
}
|
||||||
|
|
||||||
data class HoursAgo(val hours: Int) : DateTimeAgo() {
|
data class HoursAgo(val hours: Int) : DateTimeAgo() {
|
||||||
override fun format(context: Context): String {
|
override fun format(resources: Resources): String {
|
||||||
return context.resources.getQuantityString(
|
return resources.getQuantityString(R.plurals.hours_ago, hours, hours)
|
||||||
R.plurals.hours_ago,
|
|
||||||
hours,
|
|
||||||
hours,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "hours_ago_$hours"
|
override fun toString() = "hours_ago_$hours"
|
||||||
}
|
}
|
||||||
|
|
||||||
object Today : DateTimeAgo() {
|
object Today : DateTimeAgo() {
|
||||||
override fun format(context: Context): String {
|
override fun format(resources: Resources): String {
|
||||||
return context.getString(R.string.today)
|
return resources.getString(R.string.today)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "today"
|
override fun toString() = "today"
|
||||||
@@ -55,8 +46,8 @@ sealed class DateTimeAgo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object Yesterday : DateTimeAgo() {
|
object Yesterday : DateTimeAgo() {
|
||||||
override fun format(context: Context): String {
|
override fun format(resources: Resources): String {
|
||||||
return context.getString(R.string.yesterday)
|
return resources.getString(R.string.yesterday)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "yesterday"
|
override fun toString() = "yesterday"
|
||||||
@@ -65,46 +56,44 @@ sealed class DateTimeAgo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class DaysAgo(val days: Int) : DateTimeAgo() {
|
data class DaysAgo(val days: Int) : DateTimeAgo() {
|
||||||
override fun format(context: Context): String {
|
override fun format(resources: Resources): String {
|
||||||
return context.resources.getQuantityString(R.plurals.days_ago, days, days)
|
return resources.getQuantityString(R.plurals.days_ago, days, days)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "days_ago_$days"
|
override fun toString() = "days_ago_$days"
|
||||||
}
|
}
|
||||||
|
|
||||||
data class MonthsAgo(val months: Int) : DateTimeAgo() {
|
data class MonthsAgo(val months: Int) : DateTimeAgo() {
|
||||||
override fun format(context: Context): String {
|
override fun format(resources: Resources): String {
|
||||||
return if (months == 0) {
|
return if (months == 0) {
|
||||||
context.getString(R.string.this_month)
|
resources.getString(R.string.this_month)
|
||||||
} else {
|
} else {
|
||||||
context.resources.getQuantityString(
|
resources.getQuantityString(R.plurals.months_ago, months, months)
|
||||||
R.plurals.months_ago,
|
|
||||||
months,
|
|
||||||
months,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Absolute(private val date: LocalDate) : DateTimeAgo() {
|
data class Absolute(private val date: LocalDate) : DateTimeAgo() {
|
||||||
override fun format(context: Context): String {
|
override fun format(resources: Resources): String {
|
||||||
return if (date == EPOCH_DATE) {
|
return if (date == EPOCH_DATE) {
|
||||||
context.getString(R.string.unknown)
|
resources.getString(R.string.unknown)
|
||||||
} else {
|
} else {
|
||||||
DateUtils.formatDateTime(context, date.toMillis(), DateUtils.FORMAT_SHOW_DATE)
|
date.format(formatter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "abs_${date.toEpochDay()}"
|
override fun toString() = "abs_${date.toEpochDay()}"
|
||||||
|
|
||||||
private companion object {
|
companion object {
|
||||||
val EPOCH_DATE: LocalDate = LocalDate.of(1970, 1, 1)
|
// TODO: Use Java 9's LocalDate.EPOCH.
|
||||||
|
private val EPOCH_DATE = LocalDate.of(1970, 1, 1)
|
||||||
|
private val formatter = DateTimeFormatter.ofPattern("d MMMM")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object LongAgo : DateTimeAgo() {
|
object LongAgo : DateTimeAgo() {
|
||||||
override fun format(context: Context): String {
|
override fun format(resources: Resources): String {
|
||||||
return context.getString(R.string.long_ago)
|
return resources.getString(R.string.long_ago)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "long_ago"
|
override fun toString() = "long_ago"
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ fun calculateTimeAgo(instant: Instant, showMonths: Boolean = false): DateTimeAgo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("KotlinConstantConditions")
|
|
||||||
fun Long.toInstantOrNull() = if (this == 0L) null else Instant.ofEpochMilli(this)
|
fun Long.toInstantOrNull() = if (this == 0L) null else Instant.ofEpochMilli(this)
|
||||||
|
|
||||||
fun Resources.formatDurationShort(millis: Long): String? {
|
fun Resources.formatDurationShort(millis: Long): String? {
|
||||||
@@ -51,5 +50,3 @@ fun Resources.formatDurationShort(millis: Long): String? {
|
|||||||
else -> getString(R.string.seconds_short, seconds)
|
else -> getString(R.string.seconds_short, seconds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun LocalDate.toMillis(): Long = atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli()
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ data class ListHeader private constructor(
|
|||||||
fun getText(context: Context): CharSequence? = when (textRaw) {
|
fun getText(context: Context): CharSequence? = when (textRaw) {
|
||||||
is CharSequence -> textRaw
|
is CharSequence -> textRaw
|
||||||
is Int -> if (textRaw != 0) context.getString(textRaw) else null
|
is Int -> if (textRaw != 0) context.getString(textRaw) else null
|
||||||
is DateTimeAgo -> textRaw.format(context)
|
is DateTimeAgo -> textRaw.format(context.resources)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class LocalMangaParser(private val uri: Uri) {
|
|||||||
mangaInfo.copy(
|
mangaInfo.copy(
|
||||||
source = LocalMangaSource,
|
source = LocalMangaSource,
|
||||||
url = rootFile.toUri().toString(),
|
url = rootFile.toUri().toString(),
|
||||||
coverUrl = coverEntry?.let { uri.child(it, resolve = true).toString() },
|
coverUrl = coverEntry?.let { uri.child(it, resolve = true).toString() }.orEmpty(),
|
||||||
largeCoverUrl = null,
|
largeCoverUrl = null,
|
||||||
chapters = if (withDetails) {
|
chapters = if (withDetails) {
|
||||||
mangaInfo.chapters?.mapNotNull { c ->
|
mangaInfo.chapters?.mapNotNull { c ->
|
||||||
@@ -92,7 +92,9 @@ class LocalMangaParser(private val uri: Uri) {
|
|||||||
url = rootFile.toUri().toString(),
|
url = rootFile.toUri().toString(),
|
||||||
publicUrl = rootFile.toUri().toString(),
|
publicUrl = rootFile.toUri().toString(),
|
||||||
source = LocalMangaSource,
|
source = LocalMangaSource,
|
||||||
coverUrl = coverEntry?.let { uri.child(it, resolve = true).toString() },
|
coverUrl = coverEntry?.let {
|
||||||
|
uri.child(it, resolve = true).toString()
|
||||||
|
}.orEmpty(),
|
||||||
chapters = if (withDetails) {
|
chapters = if (withDetails) {
|
||||||
val chapters = fileSystem.listRecursively(rootPath)
|
val chapters = fileSystem.listRecursively(rootPath)
|
||||||
.mapNotNullTo(HashSet()) { path ->
|
.mapNotNullTo(HashSet()) { path ->
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class MangaStatsSheet : BaseAdaptiveSheet<SheetStatsMangaBinding>(), View.OnClic
|
|||||||
binding.chartView.barColor = KotatsuColors.ofManga(binding.root.context, viewModel.manga)
|
binding.chartView.barColor = KotatsuColors.ofManga(binding.root.context, viewModel.manga)
|
||||||
viewModel.stats.observe(viewLifecycleOwner, ::onStatsChanged)
|
viewModel.stats.observe(viewLifecycleOwner, ::onStatsChanged)
|
||||||
viewModel.startDate.observe(viewLifecycleOwner) {
|
viewModel.startDate.observe(viewLifecycleOwner) {
|
||||||
binding.textViewStart.textAndVisible = it?.format(binding.root.context)
|
binding.textViewStart.textAndVisible = it?.format(resources)
|
||||||
}
|
}
|
||||||
viewModel.totalPagesRead.observe(viewLifecycleOwner) {
|
viewModel.totalPagesRead.observe(viewLifecycleOwner) {
|
||||||
binding.textViewPages.text = getString(R.string.pages_read_s, it.format())
|
binding.textViewPages.text = getString(R.string.pages_read_s, it.format())
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ abstract class TracksDao : MangaQueryBuilder.ConditionCallback {
|
|||||||
@Query("DELETE FROM tracks WHERE manga_id = :mangaId")
|
@Query("DELETE FROM tracks WHERE manga_id = :mangaId")
|
||||||
abstract suspend fun delete(mangaId: Long)
|
abstract suspend fun delete(mangaId: Long)
|
||||||
|
|
||||||
@Query("DELETE FROM tracks WHERE manga_id NOT IN (SELECT manga_id FROM history WHERE history.deleted_at = 0 UNION SELECT manga_id FROM favourites WHERE favourites.deleted_at = 0 AND category_id IN (SELECT category_id FROM favourite_categories WHERE favourite_categories.deleted_at = 0 AND track = 1))")
|
@Query("DELETE FROM tracks WHERE manga_id NOT IN (SELECT manga_id FROM history UNION SELECT manga_id FROM favourites WHERE category_id IN (SELECT category_id FROM favourite_categories WHERE track = 1))")
|
||||||
abstract suspend fun gc()
|
abstract suspend fun gc()
|
||||||
|
|
||||||
@Upsert
|
@Upsert
|
||||||
|
|||||||
5
app/version.properties
Normal file
5
app/version.properties
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#Wed Jan 22 19:14:17 EET 2025
|
||||||
|
code=1
|
||||||
|
build=8
|
||||||
|
variant=
|
||||||
|
base=7.7
|
||||||
@@ -31,7 +31,7 @@ material = "1.12.0"
|
|||||||
moshi = "1.15.2"
|
moshi = "1.15.2"
|
||||||
okhttp = "4.12.0"
|
okhttp = "4.12.0"
|
||||||
okio = "3.9.1"
|
okio = "3.9.1"
|
||||||
parsers = "1.6"
|
parsers = "51ed1b2db8"
|
||||||
preference = "1.2.1"
|
preference = "1.2.1"
|
||||||
recyclerview = "1.3.2"
|
recyclerview = "1.3.2"
|
||||||
room = "2.6.1"
|
room = "2.6.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user