Compare commits

...

8 Commits

Author SHA1 Message Date
2374c96009 Fix source preferences summaries 2020-07-19 11:44:12 +03:00
2dd51117e9 Remove unused resources 2020-07-16 19:27:59 +03:00
6c5f3c7d97 Fix readmanga search 2020-07-16 19:20:59 +03:00
626bb20edb Fix global search 2020-07-12 13:48:52 +03:00
d363869dab Fix cbz thumbnails 2020-07-10 07:22:16 +03:00
774f33c63d Get remote manga for local in tracker 2020-07-10 07:14:41 +03:00
079427346a Update dependencies 2020-07-10 07:09:41 +03:00
a1a3125834 Fix crash on manga downloading 2020-07-06 20:05:41 +03:00
18 changed files with 58 additions and 63 deletions

View File

@@ -16,7 +16,7 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode gitCommits versionCode gitCommits
versionName '0.5-rc1' versionName '0.5'
kapt { kapt {
arguments { arguments {
@@ -65,13 +65,15 @@ dependencies {
implementation 'androidx.activity:activity-ktx:1.2.0-alpha06' implementation 'androidx.activity:activity-ktx:1.2.0-alpha06'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha06' implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha06'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-alpha05' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-alpha05'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta7' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta8'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha04' implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha04'
implementation 'androidx.viewpager2:viewpager2:1.1.0-alpha01' implementation 'androidx.viewpager2:viewpager2:1.1.0-alpha01'
implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'androidx.preference:preference-ktx:1.1.1'
implementation 'androidx.work:work-runtime-ktx:2.4.0-rc01' implementation 'androidx.work:work-runtime-ktx:2.4.0-rc01'
implementation 'com.google.android.material:material:1.3.0-alpha01' implementation 'com.google.android.material:material:1.3.0-alpha01'
//noinspection LifecycleAnnotationProcessorWithJava8
kapt 'androidx.lifecycle:lifecycle-compiler:2.3.0-alpha05'
implementation 'androidx.room:room-runtime:2.2.5' implementation 'androidx.room:room-runtime:2.2.5'
implementation 'androidx.room:room-ktx:2.2.5' implementation 'androidx.room:room-ktx:2.2.5'
@@ -83,8 +85,8 @@ dependencies {
implementation 'com.github.moxy-community:moxy-ktx:2.1.2' implementation 'com.github.moxy-community:moxy-ktx:2.1.2'
kapt 'com.github.moxy-community:moxy-compiler:2.1.2' kapt 'com.github.moxy-community:moxy-compiler:2.1.2'
implementation 'com.squareup.okhttp3:okhttp:4.7.2' implementation 'com.squareup.okhttp3:okhttp:4.8.0'
implementation 'com.squareup.okio:okio:2.6.0' implementation 'com.squareup.okio:okio:2.7.0'
implementation 'org.jsoup:jsoup:1.13.1' implementation 'org.jsoup:jsoup:1.13.1'
implementation 'org.koin:koin-android:2.1.5' implementation 'org.koin:koin-android:2.1.5'

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.core.parser
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.webkit.MimeTypeMap
import androidx.collection.ArraySet import androidx.collection.ArraySet
import androidx.core.net.toFile import androidx.core.net.toFile
import androidx.core.net.toUri import androidx.core.net.toUri
@@ -91,7 +92,7 @@ class LocalMangaRepository : MangaRepository, KoinComponent {
coverUrl = zipUri( coverUrl = zipUri(
file, file,
entryName = index.getCoverEntry() entryName = index.getCoverEntry()
?: findFirstEntry(zip.entries())?.name.orEmpty() ?: findFirstEntry(zip.entries(), isImage = true)?.name.orEmpty()
), ),
chapters = info.chapters?.map { c -> c.copy(url = fileUri) } chapters = info.chapters?.map { c -> c.copy(url = fileUri) }
) )
@@ -110,7 +111,7 @@ class LocalMangaRepository : MangaRepository, KoinComponent {
title = title, title = title,
url = fileUri, url = fileUri,
source = MangaSource.LOCAL, source = MangaSource.LOCAL,
coverUrl = zipUri(file, findFirstEntry(zip.entries())?.name.orEmpty()), coverUrl = zipUri(file, findFirstEntry(zip.entries(), isImage = true)?.name.orEmpty()),
chapters = chapters.sortedWith(AlphanumComparator()).mapIndexed { i, s -> chapters = chapters.sortedWith(AlphanumComparator()).mapIndexed { i, s ->
MangaChapter( MangaChapter(
id = "$i$s".longHashCode(), id = "$i$s".longHashCode(),
@@ -136,11 +137,19 @@ class LocalMangaRepository : MangaRepository, KoinComponent {
private fun zipUri(file: File, entryName: String) = private fun zipUri(file: File, entryName: String) =
Uri.fromParts("cbz", file.path, entryName).toString() Uri.fromParts("cbz", file.path, entryName).toString()
private fun findFirstEntry(entries: Enumeration<out ZipEntry>): ZipEntry? { private fun findFirstEntry(entries: Enumeration<out ZipEntry>, isImage: Boolean): ZipEntry? {
val list = entries.toList() val list = entries.toList()
.filterNot { it.isDirectory } .filterNot { it.isDirectory }
.sortedWith(compareBy(AlphanumComparator()) { x -> x.name }) .sortedWith(compareBy(AlphanumComparator()) { x -> x.name })
return list.firstOrNull() return if (isImage) {
val map = MimeTypeMap.getSingleton()
list.firstOrNull {
map.getMimeTypeFromExtension(it.name.substringAfterLast('.'))
?.startsWith("image/") == true
}
} else {
list.firstOrNull()
}
} }
override val sortOrders = emptySet<SortOrder>() override val sortOrders = emptySet<SortOrder>()

View File

@@ -28,7 +28,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
val doc = when { val doc = when {
!query.isNullOrEmpty() -> loaderContext.httpPost( !query.isNullOrEmpty() -> loaderContext.httpPost(
"https://$domain/search", "https://$domain/search",
mapOf("q" to query, "offset" to offset.toString()) mapOf("q" to query.urlEncoded(), "offset" to offset.toString())
) )
tag == null -> loaderContext.httpGet( tag == null -> loaderContext.httpGet(
"https://$domain/list?sortType=${getSortKey( "https://$domain/list?sortType=${getSortKey(

View File

@@ -5,6 +5,6 @@ import org.koitharu.kotatsu.domain.MangaLoaderContext
class ReadmangaRepository(loaderContext: MangaLoaderContext) : GroupleRepository(loaderContext) { class ReadmangaRepository(loaderContext: MangaLoaderContext) : GroupleRepository(loaderContext) {
override val defaultDomain = "readmanga.me" override val defaultDomain = "readmanga.live"
override val source = MangaSource.READMANGA_RU override val source = MangaSource.READMANGA_RU
} }

View File

@@ -18,7 +18,12 @@ class MangaSearchRepository : KoinComponent {
var isEmitted = false var isEmitted = false
for (source in sources) { for (source in sources) {
val list = lists.getOrPut(source) { val list = lists.getOrPut(source) {
MangaProviderFactory.create(source).getList(0, query, SortOrder.POPULARITY) try {
MangaProviderFactory.create(source).getList(0, query, SortOrder.POPULARITY)
} catch (e: Throwable) {
e.printStackTrace()
emptyList<Manga>()
}
} }
if (i < list.size) { if (i < list.size) {
emit(list.subList(i, (i + batchSize).coerceAtMost(list.lastIndex))) emit(list.subList(i, (i + batchSize).coerceAtMost(list.lastIndex)))

View File

@@ -6,10 +6,8 @@ import org.koin.core.inject
import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.entity.TrackEntity import org.koitharu.kotatsu.core.db.entity.TrackEntity
import org.koitharu.kotatsu.core.db.entity.TrackLogEntity import org.koitharu.kotatsu.core.db.entity.TrackLogEntity
import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.core.model.MangaChapter import org.koitharu.kotatsu.domain.MangaProviderFactory
import org.koitharu.kotatsu.core.model.MangaTracking
import org.koitharu.kotatsu.core.model.TrackingLogItem
import java.util.* import java.util.*
class TrackingRepository : KoinComponent { class TrackingRepository : KoinComponent {
@@ -24,12 +22,16 @@ class TrackingRepository : KoinComponent {
suspend fun getAllTracks(): List<MangaTracking> { suspend fun getAllTracks(): List<MangaTracking> {
val favourites = db.favouritesDao.findAllManga() val favourites = db.favouritesDao.findAllManga()
val history = db.historyDao.findAllManga() val history = db.historyDao.findAllManga()
val manga = (favourites + history).distinctBy { it.id } val mangas = (favourites + history).distinctBy { it.id }
val tracks = db.tracksDao.findAll().groupBy { it.mangaId } val tracks = db.tracksDao.findAll().groupBy { it.mangaId }
return manga.map { m -> return mangas.mapNotNull { me ->
val track = tracks[m.id]?.singleOrNull() var manga = me.toManga()
if (manga.source == MangaSource.LOCAL) {
manga = MangaProviderFactory.createLocal().getRemoteManga(manga) ?: return@mapNotNull null
}
val track = tracks[manga.id]?.singleOrNull()
MangaTracking( MangaTracking(
manga = m.toManga(), manga = manga,
knownChaptersCount = track?.totalChapters ?: -1, knownChaptersCount = track?.totalChapters ?: -1,
lastChapterId = track?.lastChapterId ?: 0L, lastChapterId = track?.lastChapterId ?: 0L,
lastNotifiedChapterId = track?.lastNotifiedChapterId ?: 0L, lastNotifiedChapterId = track?.lastNotifiedChapterId ?: 0L,

View File

@@ -28,7 +28,7 @@ class ChapterHolder(parent: ViewGroup) :
} }
ChapterExtra.CURRENT -> { ChapterExtra.CURRENT -> {
textView_number.setBackgroundResource(R.drawable.bg_badge_outline_accent) textView_number.setBackgroundResource(R.drawable.bg_badge_outline_accent)
textView_number.setTextColor(context.getThemeColor(R.attr.colorAccent)) textView_number.setTextColor(context.getThemeColor(androidx.appcompat.R.attr.colorAccent))
} }
ChapterExtra.NEW -> { ChapterExtra.NEW -> {
textView_number.setBackgroundResource(R.drawable.bg_badge_accent) textView_number.setBackgroundResource(R.drawable.bg_badge_accent)

View File

@@ -206,7 +206,7 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView,
override fun onSupportActionModeFinished(mode: ActionMode) { override fun onSupportActionModeFinished(mode: ActionMode) {
super.onSupportActionModeFinished(mode) super.onSupportActionModeFinished(mode)
pager.isUserInputEnabled = true pager.isUserInputEnabled = true
window?.statusBarColor = getThemeColor(R.attr.colorPrimaryDark) window?.statusBarColor = getThemeColor(androidx.appcompat.R.attr.colorPrimaryDark)
} }
companion object { companion object {

View File

@@ -77,9 +77,9 @@ class DownloadService : BaseService() {
return launch(Dispatchers.IO) { return launch(Dispatchers.IO) {
mutex.lock() mutex.lock()
wakeLock.acquire(TimeUnit.HOURS.toMillis(1)) wakeLock.acquire(TimeUnit.HOURS.toMillis(1))
notification.fillFrom(manga)
notification.setCancelId(startId)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
notification.fillFrom(manga)
notification.setCancelId(startId)
startForeground(DownloadNotification.NOTIFICATION_ID, notification()) startForeground(DownloadNotification.NOTIFICATION_ID, notification())
} }
val destination = settings.getStorageDir(this@DownloadService) val destination = settings.getStorageDir(this@DownloadService)
@@ -94,10 +94,8 @@ class DownloadService : BaseService() {
.build() .build()
).drawable ).drawable
} }
withContext(Dispatchers.Main) { notification.setLargeIcon(cover)
notification.setLargeIcon(cover) notification.update()
notification.update()
}
val data = if (manga.chapters == null) repo.getDetails(manga) else manga val data = if (manga.chapters == null) repo.getDetails(manga) else manga
output = MangaZip.findInDir(destination, data) output = MangaZip.findInDir(destination, data)
output.prepare(data) output.prepare(data)
@@ -141,31 +139,25 @@ class DownloadService : BaseService() {
} }
} }
} }
withContext(Dispatchers.Main) { notification.setCancelId(0)
notification.setCancelId(0) notification.setPostProcessing()
notification.setPostProcessing() notification.update()
notification.update()
}
output.compress() output.compress()
val result = MangaProviderFactory.createLocal().getFromFile(output.file) val result = MangaProviderFactory.createLocal().getFromFile(output.file)
withContext(Dispatchers.Main) { notification.setDone(result)
notification.setDone(result) notification.dismiss()
notification.dismiss() notification.update(manga.id.toInt().absoluteValue)
notification.update(manga.id.toInt().absoluteValue)
}
} catch (_: CancellationException) { } catch (_: CancellationException) {
withContext(Dispatchers.Main + NonCancellable) { withContext(NonCancellable) {
notification.setCancelling() notification.setCancelling()
notification.setCancelId(0) notification.setCancelId(0)
notification.update() notification.update()
} }
} catch (e: Throwable) { } catch (e: Throwable) {
withContext(Dispatchers.Main) { notification.setError(e)
notification.setError(e) notification.setCancelId(0)
notification.setCancelId(0) notification.dismiss()
notification.dismiss() notification.update(manga.id.toInt().absoluteValue)
notification.update(manga.id.toInt().absoluteValue)
}
} finally { } finally {
withContext(NonCancellable) { withContext(NonCancellable) {
jobs.remove(startId) jobs.remove(startId)

View File

@@ -17,17 +17,13 @@ class SourceSettingsFragment : PreferenceFragmentCompat(), KoinComponent {
requireArguments().getParcelable<MangaSource>(EXTRA_SOURCE)!! requireArguments().getParcelable<MangaSource>(EXTRA_SOURCE)!!
} }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
preferenceManager.sharedPreferencesName = source.name
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
activity?.title = source.title activity?.title = source.title
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.sharedPreferencesName = source.name
val repo = MangaProviderFactory.create(source) as? RemoteMangaRepository ?: return val repo = MangaProviderFactory.create(source) as? RemoteMangaRepository ?: return
val keys = repo.onCreatePreferences().map(::getString) val keys = repo.onCreatePreferences().map(::getString)
addPreferencesFromResource(R.xml.pref_source) addPreferencesFromResource(R.xml.pref_source)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M13,5V11H14.17L12,13.17L9.83,11H11V5H13M15,3H9V9H5L12,16L19,9H15V3M19,18H5V20H19V18Z" />
</vector>

View File

@@ -6,7 +6,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.2.0-alpha03' classpath 'com.android.tools.build:gradle:4.2.0-alpha04'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong

View File

@@ -18,4 +18,5 @@ android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete": # Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official kotlin.code.style=official
android.nonTransitiveRClass=true