Merge branch 'devel' into next
This commit is contained in:
@@ -81,7 +81,7 @@ afterEvaluate {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
//noinspection GradleDependency
|
//noinspection GradleDependency
|
||||||
implementation('com.github.KotatsuApp:kotatsu-parsers:06a043d290') {
|
implementation('com.github.KotatsuApp:kotatsu-parsers:a1598fd712') {
|
||||||
exclude group: 'org.json', module: 'json'
|
exclude group: 'org.json', module: 'json'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,8 +127,8 @@ dependencies {
|
|||||||
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl:4.3.2'
|
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl:4.3.2'
|
||||||
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl-viewbinding:4.3.2'
|
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl-viewbinding:4.3.2'
|
||||||
|
|
||||||
implementation 'com.google.dagger:hilt-android:2.46.1'
|
implementation 'com.google.dagger:hilt-android:2.47'
|
||||||
kapt 'com.google.dagger:hilt-compiler:2.46.1'
|
kapt 'com.google.dagger:hilt-compiler:2.47'
|
||||||
implementation 'androidx.hilt:hilt-work:1.0.0'
|
implementation 'androidx.hilt:hilt-work:1.0.0'
|
||||||
kapt 'androidx.hilt:hilt-compiler:1.0.0'
|
kapt 'androidx.hilt:hilt-compiler:1.0.0'
|
||||||
|
|
||||||
@@ -157,6 +157,6 @@ dependencies {
|
|||||||
androidTestImplementation 'androidx.room:room-testing:2.5.2'
|
androidTestImplementation 'androidx.room:room-testing:2.5.2'
|
||||||
androidTestImplementation 'com.squareup.moshi:moshi-kotlin:1.15.0'
|
androidTestImplementation 'com.squareup.moshi:moshi-kotlin:1.15.0'
|
||||||
|
|
||||||
androidTestImplementation 'com.google.dagger:hilt-android-testing:2.46.1'
|
androidTestImplementation 'com.google.dagger:hilt-android-testing:2.47'
|
||||||
kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.46.1'
|
kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.47'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.koitharu.kotatsu.bookmarks.domain
|
package org.koitharu.kotatsu.bookmarks.domain
|
||||||
|
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||||
|
import org.koitharu.kotatsu.local.data.ImageFileFilter
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
@@ -37,7 +38,8 @@ class Bookmark(
|
|||||||
)
|
)
|
||||||
|
|
||||||
private fun isImageUrlDirect(): Boolean {
|
private fun isImageUrlDirect(): Boolean {
|
||||||
return imageUrl.substringAfterLast('.').length in 2..4
|
val extension = imageUrl.substringAfterLast('.')
|
||||||
|
return extension.isNotEmpty() && ImageFileFilter().isExtensionValid(extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
|
|||||||
@@ -5,15 +5,19 @@ import coil.ImageLoader
|
|||||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
||||||
|
import org.koitharu.kotatsu.core.ui.drawable.TextDrawable
|
||||||
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
|
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
|
||||||
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
|
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
|
||||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||||
import org.koitharu.kotatsu.core.util.ext.decodeRegion
|
import org.koitharu.kotatsu.core.util.ext.decodeRegion
|
||||||
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
|
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
|
||||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.getThemeResId
|
||||||
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||||
import org.koitharu.kotatsu.core.util.ext.source
|
import org.koitharu.kotatsu.core.util.ext.source
|
||||||
import org.koitharu.kotatsu.databinding.ItemBookmarkBinding
|
import org.koitharu.kotatsu.databinding.ItemBookmarkBinding
|
||||||
|
import org.koitharu.kotatsu.parsers.util.format
|
||||||
|
import com.google.android.material.R as materialR
|
||||||
|
|
||||||
fun bookmarkListAD(
|
fun bookmarkListAD(
|
||||||
coil: ImageLoader,
|
coil: ImageLoader,
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package org.koitharu.kotatsu.core.ui.drawable
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.ColorFilter
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.graphics.PixelFormat
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.os.Build
|
||||||
|
import android.text.Layout
|
||||||
|
import android.text.StaticLayout
|
||||||
|
import android.text.TextPaint
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.annotation.Px
|
||||||
|
import androidx.annotation.StyleRes
|
||||||
|
import androidx.core.graphics.withTranslation
|
||||||
|
import com.google.android.material.resources.TextAppearance
|
||||||
|
import com.google.android.material.resources.TextAppearanceFontCallback
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.getThemeColor
|
||||||
|
|
||||||
|
class TextDrawable(
|
||||||
|
val text: CharSequence,
|
||||||
|
) : Drawable() {
|
||||||
|
|
||||||
|
private val paint = TextPaint(Paint.ANTI_ALIAS_FLAG)
|
||||||
|
private var cachedLayout: StaticLayout? = null
|
||||||
|
|
||||||
|
@SuppressLint("RestrictedApi")
|
||||||
|
constructor(context: Context, text: CharSequence, @StyleRes textAppearanceId: Int) : this(text) {
|
||||||
|
val ta = TextAppearance(context, textAppearanceId)
|
||||||
|
paint.color = ta.textColor?.defaultColor ?: context.getThemeColor(android.R.attr.textColorPrimary, Color.BLACK)
|
||||||
|
paint.typeface = ta.fallbackFont
|
||||||
|
ta.getFontAsync(
|
||||||
|
context, paint,
|
||||||
|
object : TextAppearanceFontCallback() {
|
||||||
|
override fun onFontRetrieved(typeface: Typeface?, fontResolvedSynchronously: Boolean) = Unit
|
||||||
|
override fun onFontRetrievalFailed(reason: Int) = Unit
|
||||||
|
},
|
||||||
|
)
|
||||||
|
paint.letterSpacing = ta.letterSpacing
|
||||||
|
}
|
||||||
|
|
||||||
|
var alignment = Layout.Alignment.ALIGN_NORMAL
|
||||||
|
|
||||||
|
var lineSpacingMultiplier = 1f
|
||||||
|
|
||||||
|
@Px
|
||||||
|
var lineSpacingExtra = 0f
|
||||||
|
|
||||||
|
@get:ColorInt
|
||||||
|
var textColor: Int
|
||||||
|
get() = paint.color
|
||||||
|
set(@ColorInt value) {
|
||||||
|
paint.color = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun draw(canvas: Canvas) {
|
||||||
|
val b = bounds
|
||||||
|
if (b.isEmpty) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
canvas.withTranslation(x = b.left.toFloat(), y = b.top.toFloat()) {
|
||||||
|
obtainLayout().draw(canvas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setAlpha(alpha: Int) {
|
||||||
|
paint.alpha = alpha
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setColorFilter(colorFilter: ColorFilter?) {
|
||||||
|
paint.setColorFilter(colorFilter)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
|
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
||||||
|
|
||||||
|
private fun obtainLayout(): StaticLayout {
|
||||||
|
val width = bounds.width()
|
||||||
|
cachedLayout?.let {
|
||||||
|
if (it.width == width) {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
StaticLayout.Builder.obtain(text, 0, text.length, paint, width)
|
||||||
|
.setAlignment(alignment)
|
||||||
|
.setLineSpacing(lineSpacingExtra, lineSpacingMultiplier)
|
||||||
|
.setIncludePad(true)
|
||||||
|
.build()
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
StaticLayout(text, paint, width, alignment, lineSpacingMultiplier, lineSpacingExtra, true)
|
||||||
|
}.also { cachedLayout = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,6 +66,13 @@ fun Context.getThemeColorStateList(
|
|||||||
it.getColorStateList(0)
|
it.getColorStateList(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Context.getThemeResId(
|
||||||
|
@AttrRes resId: Int,
|
||||||
|
fallback: Int
|
||||||
|
): Int = obtainStyledAttributes(intArrayOf(resId)).use {
|
||||||
|
it.getResourceId(0, fallback)
|
||||||
|
}
|
||||||
|
|
||||||
fun TypedArray.getDrawableCompat(context: Context, index: Int): Drawable? {
|
fun TypedArray.getDrawableCompat(context: Context, index: Int): Drawable? {
|
||||||
val resId = getResourceId(index, 0)
|
val resId = getResourceId(index, 0)
|
||||||
return if (resId != 0) ContextCompat.getDrawable(context, resId) else null
|
return if (resId != 0) ContextCompat.getDrawable(context, resId) else null
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class ImageFileFilter : FilenameFilter, FileFilter {
|
|||||||
return isExtensionValid(ext)
|
return isExtensionValid(ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isExtensionValid(ext: String): Boolean {
|
fun isExtensionValid(ext: String): Boolean {
|
||||||
return ext == "png" || ext == "jpg" || ext == "jpeg" || ext == "webp"
|
return ext == "png" || ext == "jpg" || ext == "jpeg" || ext == "webp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ enum class ScoreFormat {
|
|||||||
|
|
||||||
POINT_5 -> score / 5f
|
POINT_5 -> score / 5f
|
||||||
POINT_3 -> score / 3f
|
POINT_3 -> score / 3f
|
||||||
}
|
}.coerceIn(0f, 1f)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ class MALRepository @Inject constructor(
|
|||||||
status = json.getString("status"),
|
status = json.getString("status"),
|
||||||
chapter = json.getInt("num_chapters_read"),
|
chapter = json.getInt("num_chapters_read"),
|
||||||
comment = json.getString("comments"),
|
comment = json.getString("comments"),
|
||||||
rating = json.getDouble("score").toFloat() / 10f,
|
rating = (json.getDouble("score").toFloat() / 10f).coerceIn(0f, 1f),
|
||||||
)
|
)
|
||||||
db.scrobblingDao.upsert(entity)
|
db.scrobblingDao.upsert(entity)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ class ShikimoriRepository @Inject constructor(
|
|||||||
status = json.getString("status"),
|
status = json.getString("status"),
|
||||||
chapter = json.getInt("chapters"),
|
chapter = json.getInt("chapters"),
|
||||||
comment = json.getString("text"),
|
comment = json.getString("text"),
|
||||||
rating = json.getDouble("score").toFloat() / 10f,
|
rating = (json.getDouble("score").toFloat() / 10f).coerceIn(0f, 1f),
|
||||||
)
|
)
|
||||||
db.scrobblingDao.upsert(entity)
|
db.scrobblingDao.upsert(entity)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import kotlinx.coroutines.flow.onStart
|
|||||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.core.prefs.observeAsFlow
|
|
||||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||||
import org.koitharu.kotatsu.favourites.data.toFavouriteCategory
|
import org.koitharu.kotatsu.favourites.data.toFavouriteCategory
|
||||||
import org.koitharu.kotatsu.favourites.data.toMangaList
|
import org.koitharu.kotatsu.favourites.data.toMangaList
|
||||||
@@ -52,8 +51,8 @@ class ShelfContentObserveUseCase @Inject constructor(
|
|||||||
private fun observeLocalManga(sortOrder: SortOrder, limit: Int): Flow<List<Manga>> {
|
private fun observeLocalManga(sortOrder: SortOrder, limit: Int): Flow<List<Manga>> {
|
||||||
return combine<LocalManga?, String, Any?>(
|
return combine<LocalManga?, String, Any?>(
|
||||||
localStorageChanges,
|
localStorageChanges,
|
||||||
settings.observe().filter { it == AppSettings.KEY_LOCAL_MANGA_DIRS }
|
settings.observe().filter { it == AppSettings.KEY_LOCAL_MANGA_DIRS }.onStart { emit("") }
|
||||||
) { _, _ -> Any() }
|
) { a, b -> a to b }
|
||||||
.onStart { emit(null) }
|
.onStart { emit(null) }
|
||||||
.mapLatest {
|
.mapLatest {
|
||||||
localMangaRepository.getList(0, null, sortOrder).take(limit)
|
localMangaRepository.getList(0, null, sortOrder).take(limit)
|
||||||
|
|||||||
@@ -225,4 +225,8 @@
|
|||||||
<string name="various_languages">विभिन्न भाषाहरू</string>
|
<string name="various_languages">विभिन्न भाषाहरू</string>
|
||||||
<string name="search_chapters">अध्याय खोज्नुहोस्</string>
|
<string name="search_chapters">अध्याय खोज्नुहोस्</string>
|
||||||
<string name="appearance">उपस्थिति</string>
|
<string name="appearance">उपस्थिति</string>
|
||||||
|
<string name="history_shortcuts">हालैको मंगा सर्टकट देखाउनुहोस्</string>
|
||||||
|
<string name="reader_control_ltr_summary">दायाँ किनारामा ट्याप गर्नुहोस् वा दायाँ कुञ्जी थिच्दा सधैं अर्को पृष्ठमा स्विच हुन्छ</string>
|
||||||
|
<string name="reader_control_ltr">Ergonomic पाठक नियन्त्रण</string>
|
||||||
|
<string name="manga_error_description_pattern">त्रुटि विवरण:<br> <tt>%1$s</tt><br><br> 1. <a href=%2$s>वेब ब्राउजरमा मंगा खोल्ने</a> प्रयास गर्नुहोस् कि यो यसको स्रोतमा उपलब्ध छ<br> 2. निश्चित गर्नुहोस् कि तपाइँ <a href=kotatsu://about>Kotatsu को नवीनतम संस्करण</a> प्रयोग गर्दै हुनुहुन्छ<br> 3. यदि यो उपलब्ध छ भने, विकासकर्ताहरूलाई त्रुटि रिपोर्ट पठाउनुहोस्।</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -389,7 +389,7 @@
|
|||||||
<string name="address">Địa chỉ</string>
|
<string name="address">Địa chỉ</string>
|
||||||
<string name="invert_colors">Đảo màu</string>
|
<string name="invert_colors">Đảo màu</string>
|
||||||
<string name="invalid_port_number">Cổng không hợp lệ</string>
|
<string name="invalid_port_number">Cổng không hợp lệ</string>
|
||||||
<string name="download_option_manual_selection">Chọn các chương bằng tay</string>
|
<string name="download_option_manual_selection">Chọn thủ công các chương</string>
|
||||||
<string name="download_option_all_unread">Tất cả các chương chưa đọc</string>
|
<string name="download_option_all_unread">Tất cả các chương chưa đọc</string>
|
||||||
<string name="resume">Tiếp tục</string>
|
<string name="resume">Tiếp tục</string>
|
||||||
<string name="clear_new_chapters_counters">Xoá thông tin về chương mới</string>
|
<string name="clear_new_chapters_counters">Xoá thông tin về chương mới</string>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.0.2'
|
classpath 'com.android.tools.build:gradle:8.0.2'
|
||||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22'
|
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22'
|
||||||
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.46.1'
|
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.47'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user