mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-23 18:51:51 +01:00
Some minor stuff from upstream (#547)
* local manga changes from stable * use device pin instead of biometric when biometric cant be used for some reason * corektx changes Co-authored-by: arkon <arkon@users.noreply.github.com>
This commit is contained in:
parent
45eab517d0
commit
c0228f06f8
@ -90,7 +90,7 @@ dependencies {
|
|||||||
implementation("com.github.inorichi:subsampling-scale-image-view:ac0dae7")
|
implementation("com.github.inorichi:subsampling-scale-image-view:ac0dae7")
|
||||||
implementation("com.github.inorichi:junrar-android:634c1f5")
|
implementation("com.github.inorichi:junrar-android:634c1f5")
|
||||||
|
|
||||||
// Android support library
|
// Android X libraries
|
||||||
implementation("androidx.appcompat:appcompat:1.1.0")
|
implementation("androidx.appcompat:appcompat:1.1.0")
|
||||||
implementation("androidx.cardview:cardview:1.0.0")
|
implementation("androidx.cardview:cardview:1.0.0")
|
||||||
implementation("com.google.android.material:material:1.1.0")
|
implementation("com.google.android.material:material:1.1.0")
|
||||||
@ -100,12 +100,13 @@ dependencies {
|
|||||||
implementation("androidx.browser:browser:1.2.0")
|
implementation("androidx.browser:browser:1.2.0")
|
||||||
implementation("androidx.biometric:biometric:1.0.1")
|
implementation("androidx.biometric:biometric:1.0.1")
|
||||||
implementation("androidx.palette:palette:1.0.0")
|
implementation("androidx.palette:palette:1.0.0")
|
||||||
|
implementation ("androidx.core:core-ktx:$1.3.1")
|
||||||
|
|
||||||
implementation("androidx.constraintlayout:constraintlayout:1.1.3")
|
implementation("androidx.constraintlayout:constraintlayout:1.1.3")
|
||||||
|
|
||||||
implementation("androidx.multidex:multidex:2.0.1")
|
implementation("androidx.multidex:multidex:2.0.1")
|
||||||
|
|
||||||
implementation("com.google.firebase:firebase-core:17.3.0")
|
implementation("com.google.firebase:firebase-core:17.4.4")
|
||||||
|
|
||||||
val lifecycleVersion = "2.2.0"
|
val lifecycleVersion = "2.2.0"
|
||||||
implementation("androidx.lifecycle:lifecycle-extensions:$lifecycleVersion")
|
implementation("androidx.lifecycle:lifecycle-extensions:$lifecycleVersion")
|
||||||
|
@ -7,6 +7,7 @@ import android.net.Uri
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
||||||
@ -108,7 +109,7 @@ class BackupCreateService : Service() {
|
|||||||
val backupFlags = intent.getIntExtra(BackupConst.EXTRA_FLAGS, 0)
|
val backupFlags = intent.getIntExtra(BackupConst.EXTRA_FLAGS, 0)
|
||||||
backupManager = BackupManager(this)
|
backupManager = BackupManager(this)
|
||||||
|
|
||||||
val backupFileUri = Uri.parse(backupManager.createBackup(uri, backupFlags, false))
|
val backupFileUri = backupManager.createBackup(uri, backupFlags, false)?.toUri()
|
||||||
val unifile = UniFile.fromUri(this, backupFileUri)
|
val unifile = UniFile.fromUri(this, backupFileUri)
|
||||||
notifier.showBackupComplete(unifile)
|
notifier.showBackupComplete(unifile)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.backup
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
import androidx.work.PeriodicWorkRequestBuilder
|
import androidx.work.PeriodicWorkRequestBuilder
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
@ -19,7 +20,7 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
val preferences = Injekt.get<PreferencesHelper>()
|
val preferences = Injekt.get<PreferencesHelper>()
|
||||||
val backupManager = BackupManager(context)
|
val backupManager = BackupManager(context)
|
||||||
val uri = Uri.parse(preferences.backupsDirectory().getOrDefault())
|
val uri = preferences.backupsDirectory().getOrDefault().toUri()
|
||||||
val flags = BackupCreateService.BACKUP_ALL
|
val flags = BackupCreateService.BACKUP_ALL
|
||||||
return try {
|
return try {
|
||||||
backupManager.createBackup(uri, flags, true)
|
backupManager.createBackup(uri, flags, true)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.data.download
|
package eu.kanade.tachiyomi.data.download
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import androidx.core.net.toUri
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
@ -57,7 +57,7 @@ class DownloadCache(
|
|||||||
*/
|
*/
|
||||||
private fun getDirectoryFromPreference(): UniFile {
|
private fun getDirectoryFromPreference(): UniFile {
|
||||||
val dir = preferences.downloadsDirectory().getOrDefault()
|
val dir = preferences.downloadsDirectory().getOrDefault()
|
||||||
return UniFile.fromUri(context, Uri.parse(dir))
|
return UniFile.fromUri(context, dir.toUri())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.download
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
@ -31,14 +32,14 @@ class DownloadProvider(private val context: Context) {
|
|||||||
* The root directory for downloads.
|
* The root directory for downloads.
|
||||||
*/
|
*/
|
||||||
private var downloadsDir = preferences.downloadsDirectory().getOrDefault().let {
|
private var downloadsDir = preferences.downloadsDirectory().getOrDefault().let {
|
||||||
val dir = UniFile.fromUri(context, Uri.parse(it))
|
val dir = UniFile.fromUri(context, it.toUri())
|
||||||
DiskUtil.createNoMediaFile(dir, context)
|
DiskUtil.createNoMediaFile(dir, context)
|
||||||
dir
|
dir
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
preferences.downloadsDirectory().asObservable().skip(1)
|
preferences.downloadsDirectory().asObservable().skip(1)
|
||||||
.subscribe { downloadsDir = UniFile.fromUri(context, Uri.parse(it)) }
|
.subscribe { downloadsDir = UniFile.fromUri(context, it.toUri()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.data.track.anilist
|
package eu.kanade.tachiyomi.data.track.anilist
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.github.salomonbrys.kotson.array
|
import com.github.salomonbrys.kotson.array
|
||||||
import com.github.salomonbrys.kotson.get
|
import com.github.salomonbrys.kotson.get
|
||||||
import com.github.salomonbrys.kotson.jsonObject
|
import com.github.salomonbrys.kotson.jsonObject
|
||||||
@ -232,7 +233,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
return baseMangaUrl + mediaId
|
return baseMangaUrl + mediaId
|
||||||
}
|
}
|
||||||
|
|
||||||
fun authUrl() = Uri.parse("${baseUrl}oauth/authorize").buildUpon()
|
fun authUrl() = "${baseUrl.toUri()}oauth/authorize".toUri().buildUpon()
|
||||||
.appendQueryParameter("client_id", clientId)
|
.appendQueryParameter("client_id", clientId)
|
||||||
.appendQueryParameter("response_type", "token")
|
.appendQueryParameter("response_type", "token")
|
||||||
.build()!!
|
.build()!!
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.data.track.bangumi
|
package eu.kanade.tachiyomi.data.track.bangumi
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.github.salomonbrys.kotson.array
|
import com.github.salomonbrys.kotson.array
|
||||||
import com.github.salomonbrys.kotson.obj
|
import com.github.salomonbrys.kotson.obj
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
@ -56,9 +57,8 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
|||||||
|
|
||||||
suspend fun search(search: String): List<TrackSearch> {
|
suspend fun search(search: String): List<TrackSearch> {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val url = Uri.parse(
|
val url = "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}"
|
||||||
"$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}"
|
.toUri().buildUpon().appendQueryParameter("max_results", "20").build()
|
||||||
).buildUpon().appendQueryParameter("max_results", "20").build()
|
|
||||||
val request = Request.Builder().url(url.toString()).get().build()
|
val request = Request.Builder().url(url.toString()).get().build()
|
||||||
|
|
||||||
val netResponse = authClient.newCall(request).await()
|
val netResponse = authClient.newCall(request).await()
|
||||||
@ -159,7 +159,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
|||||||
return "$baseMangaUrl/$remoteId"
|
return "$baseMangaUrl/$remoteId"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun authUrl() = Uri.parse(loginUrl).buildUpon().appendQueryParameter("client_id", clientId)
|
fun authUrl() = loginUrl.toUri().buildUpon().appendQueryParameter("client_id", clientId)
|
||||||
.appendQueryParameter("response_type", "code")
|
.appendQueryParameter("response_type", "code")
|
||||||
.appendQueryParameter("redirect_uri", redirectUrl).build()
|
.appendQueryParameter("redirect_uri", redirectUrl).build()
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.data.track.myanimelist
|
package eu.kanade.tachiyomi.data.track.myanimelist
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
@ -182,31 +183,31 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||||||
|
|
||||||
private fun mangaUrl(remoteId: Int) = baseMangaUrl + remoteId
|
private fun mangaUrl(remoteId: Int) = baseMangaUrl + remoteId
|
||||||
|
|
||||||
private fun loginUrl() = Uri.parse(baseUrl).buildUpon().appendPath("login.php").toString()
|
private fun loginUrl() = baseUrl.toUri().buildUpon().appendPath("login.php").toString()
|
||||||
|
|
||||||
private fun searchUrl(query: String): String {
|
private fun searchUrl(query: String): String {
|
||||||
val col = "c[]"
|
val col = "c[]"
|
||||||
return Uri.parse(baseUrl).buildUpon().appendPath("manga.php")
|
return baseUrl.toUri().buildUpon().appendPath("manga.php")
|
||||||
.appendQueryParameter("q", query).appendQueryParameter(col, "a")
|
.appendQueryParameter("q", query).appendQueryParameter(col, "a")
|
||||||
.appendQueryParameter(col, "b").appendQueryParameter(col, "c")
|
.appendQueryParameter(col, "b").appendQueryParameter(col, "c")
|
||||||
.appendQueryParameter(col, "d").appendQueryParameter(col, "e")
|
.appendQueryParameter(col, "d").appendQueryParameter(col, "e")
|
||||||
.appendQueryParameter(col, "g").toString()
|
.appendQueryParameter(col, "g").toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun exportListUrl() = Uri.parse(baseUrl).buildUpon().appendPath("panel.php")
|
private fun exportListUrl() = baseUrl.toUri().buildUpon().appendPath("panel.php")
|
||||||
.appendQueryParameter("go", "export").toString()
|
.appendQueryParameter("go", "export").toString()
|
||||||
|
|
||||||
private fun updateUrl() =
|
private fun updateUrl() =
|
||||||
Uri.parse(baseModifyListUrl).buildUpon().appendPath("edit.json").toString()
|
baseModifyListUrl.toUri().buildUpon().appendPath("edit.json").toString()
|
||||||
|
|
||||||
private fun removeUrl(mediaId: Int) = Uri.parse(baseModifyListUrl).buildUpon().appendPath(mediaId.toString())
|
private fun removeUrl(mediaId: Int) = baseModifyListUrl.toUri().buildUpon().appendPath(mediaId.toString())
|
||||||
.appendPath("delete").toString()
|
.appendPath("delete").toString()
|
||||||
|
|
||||||
private fun addUrl() =
|
private fun addUrl() =
|
||||||
Uri.parse(baseModifyListUrl).buildUpon().appendPath("add.json").toString()
|
baseModifyListUrl.toUri().buildUpon().appendPath("add.json").toString()
|
||||||
|
|
||||||
private fun listEntryUrl(mediaId: Int) =
|
private fun listEntryUrl(mediaId: Int) =
|
||||||
Uri.parse(baseModifyListUrl).buildUpon().appendPath(mediaId.toString())
|
baseModifyListUrl.toUri().buildUpon().appendPath(mediaId.toString())
|
||||||
.appendPath("edit").toString()
|
.appendPath("edit").toString()
|
||||||
|
|
||||||
private fun loginPostBody(username: String, password: String, csrf: String): RequestBody {
|
private fun loginPostBody(username: String, password: String, csrf: String): RequestBody {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.data.track.shikimori
|
package eu.kanade.tachiyomi.data.track.shikimori
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.github.salomonbrys.kotson.array
|
import com.github.salomonbrys.kotson.array
|
||||||
import com.github.salomonbrys.kotson.jsonObject
|
import com.github.salomonbrys.kotson.jsonObject
|
||||||
import com.github.salomonbrys.kotson.nullString
|
import com.github.salomonbrys.kotson.nullString
|
||||||
@ -52,7 +53,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||||||
suspend fun search(search: String): List<TrackSearch> {
|
suspend fun search(search: String): List<TrackSearch> {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val url =
|
val url =
|
||||||
Uri.parse("$apiUrl/mangas").buildUpon().appendQueryParameter("order", "popularity")
|
"$apiUrl/mangas".toUri().buildUpon().appendQueryParameter("order", "popularity")
|
||||||
.appendQueryParameter("search", search).appendQueryParameter("limit", "20")
|
.appendQueryParameter("search", search).appendQueryParameter("limit", "20")
|
||||||
.build()
|
.build()
|
||||||
val request = Request.Builder().url(url.toString()).get().build()
|
val request = Request.Builder().url(url.toString()).get().build()
|
||||||
@ -96,14 +97,13 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||||||
|
|
||||||
suspend fun findLibManga(track: Track, user_id: String): Track? {
|
suspend fun findLibManga(track: Track, user_id: String): Track? {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val url = Uri.parse("$apiUrl/v2/user_rates").buildUpon()
|
val url = "$apiUrl/v2/user_rates".toUri().buildUpon()
|
||||||
.appendQueryParameter("user_id", user_id)
|
.appendQueryParameter("user_id", user_id)
|
||||||
.appendQueryParameter("target_id", track.media_id.toString())
|
.appendQueryParameter("target_id", track.media_id.toString())
|
||||||
.appendQueryParameter("target_type", "Manga").build()
|
.appendQueryParameter("target_type", "Manga").build()
|
||||||
val request = Request.Builder().url(url.toString()).get().build()
|
val request = Request.Builder().url(url.toString()).get().build()
|
||||||
|
|
||||||
val urlMangas =
|
val urlMangas ="$apiUrl/mangas".toUri().buildUpon().appendPath(track.media_id.toString())
|
||||||
Uri.parse("$apiUrl/mangas").buildUpon().appendPath(track.media_id.toString())
|
|
||||||
.build()
|
.build()
|
||||||
val requestMangas = Request.Builder().url(urlMangas.toString()).get().build()
|
val requestMangas = Request.Builder().url(urlMangas.toString()).get().build()
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||||||
return "$baseMangaUrl/$remoteId"
|
return "$baseMangaUrl/$remoteId"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun authUrl() = Uri.parse(loginUrl).buildUpon().appendQueryParameter("client_id", clientId)
|
fun authUrl() = loginUrl.toUri().buildUpon().appendQueryParameter("client_id", clientId)
|
||||||
.appendQueryParameter("redirect_uri", redirectUrl)
|
.appendQueryParameter("redirect_uri", redirectUrl)
|
||||||
.appendQueryParameter("response_type", "code").build()
|
.appendQueryParameter("response_type", "code").build()
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import android.content.Intent
|
|||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||||
@ -63,7 +64,7 @@ internal class ExtensionInstaller(private val context: Context) {
|
|||||||
// Register the receiver after removing (and unregistering) the previous download
|
// Register the receiver after removing (and unregistering) the previous download
|
||||||
downloadReceiver.register()
|
downloadReceiver.register()
|
||||||
|
|
||||||
val downloadUri = Uri.parse(url)
|
val downloadUri = url.toUri()
|
||||||
val request = DownloadManager.Request(downloadUri)
|
val request = DownloadManager.Request(downloadUri)
|
||||||
.setTitle(extension.name)
|
.setTitle(extension.name)
|
||||||
.setMimeType(APK_MIME)
|
.setMimeType(APK_MIME)
|
||||||
@ -141,7 +142,7 @@ internal class ExtensionInstaller(private val context: Context) {
|
|||||||
* @param pkgName The package name of the extension to uninstall
|
* @param pkgName The package name of the extension to uninstall
|
||||||
*/
|
*/
|
||||||
fun uninstallApk(pkgName: String) {
|
fun uninstallApk(pkgName: String) {
|
||||||
val packageUri = Uri.parse("package:$pkgName")
|
val packageUri = "package:$pkgName".toUri()
|
||||||
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri)
|
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri)
|
||||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
|
||||||
|
@ -31,17 +31,19 @@ import java.util.zip.ZipFile
|
|||||||
|
|
||||||
class LocalSource(private val context: Context) : CatalogueSource {
|
class LocalSource(private val context: Context) : CatalogueSource {
|
||||||
companion object {
|
companion object {
|
||||||
|
const val ID = 0L
|
||||||
const val HELP_URL = "https://tachiyomi.org/help/guides/reading-local-manga/"
|
const val HELP_URL = "https://tachiyomi.org/help/guides/reading-local-manga/"
|
||||||
|
|
||||||
private const val COVER_NAME = "cover.jpg"
|
private const val COVER_NAME = "cover.jpg"
|
||||||
|
private val SUPPORTED_ARCHIVE_TYPES = setOf("zip", "rar", "cbr", "cbz", "epub")
|
||||||
|
|
||||||
private val POPULAR_FILTERS = FilterList(OrderBy())
|
private val POPULAR_FILTERS = FilterList(OrderBy())
|
||||||
private val LATEST_FILTERS =
|
private val LATEST_FILTERS =
|
||||||
FilterList(OrderBy().apply { state = Filter.Sort.Selection(1, false) })
|
FilterList(OrderBy().apply { state = Filter.Sort.Selection(1, false) })
|
||||||
private val LATEST_THRESHOLD = TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)
|
private val LATEST_THRESHOLD = TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)
|
||||||
const val ID = 0L
|
|
||||||
|
|
||||||
fun updateCover(context: Context, manga: SManga, input: InputStream): File? {
|
fun updateCover(context: Context, manga: SManga, input: InputStream): File? {
|
||||||
val dir = getBaseDirectories(context).firstOrNull()
|
val dir = getBaseDirectories(context).asSequence().firstOrNull()
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
input.close()
|
input.close()
|
||||||
return null
|
return null
|
||||||
@ -85,12 +87,12 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
|
|
||||||
val time =
|
val time =
|
||||||
if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L
|
if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L
|
||||||
var mangaDirs = baseDirs.mapNotNull { it.listFiles()?.toList() }.flatten().filter {
|
var mangaDirs = baseDirs
|
||||||
it.isDirectory && if (time == 0L) it.name.contains(
|
.asSequence()
|
||||||
query,
|
.mapNotNull { it.listFiles()?.toList() }.flatten()
|
||||||
ignoreCase = true
|
.filter { it.isDirectory }
|
||||||
) else it.lastModified() >= time
|
.filter { if (time == 0L) it.name.contains(query, ignoreCase = true) else it.lastModified() >= time }
|
||||||
}.distinctBy { it.name }
|
.distinctBy { it.name }
|
||||||
|
|
||||||
val state = ((if (filters.isEmpty()) POPULAR_FILTERS else filters)[0] as OrderBy).state
|
val state = ((if (filters.isEmpty()) POPULAR_FILTERS else filters)[0] as OrderBy).state
|
||||||
when (state?.index) {
|
when (state?.index) {
|
||||||
@ -134,15 +136,17 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Observable.just(MangasPage(mangas, false))
|
return Observable.just(MangasPage(mangas.toList(), false))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS)
|
override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS)
|
||||||
|
|
||||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||||
val baseDirs = getBaseDirectories(context)
|
val baseDirs = getBaseDirectories(context)
|
||||||
baseDirs.mapNotNull { File(it, manga.url).listFiles()?.toList() }
|
baseDirs
|
||||||
.flatten().filter { it.extension == "json" }.firstOrNull()?.apply {
|
.mapNotNull { File(it, manga.url).listFiles()?.toList() }
|
||||||
|
.flatten()
|
||||||
|
.filter { it.extension == "json" }.firstOrNull()?.apply {
|
||||||
val json = Gson().fromJson(
|
val json = Gson().fromJson(
|
||||||
Scanner(this).useDelimiter("\\Z").next(),
|
Scanner(this).useDelimiter("\\Z").next(),
|
||||||
JsonObject::class.java
|
JsonObject::class.java
|
||||||
@ -155,6 +159,7 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
?: manga.genre
|
?: manga.genre
|
||||||
manga.status = json["status"]?.asInt ?: manga.status
|
manga.status = json["status"]?.asInt ?: manga.status
|
||||||
}
|
}
|
||||||
|
|
||||||
val url = manga.url
|
val url = manga.url
|
||||||
// Try to find the cover
|
// Try to find the cover
|
||||||
for (dir in baseDirs) {
|
for (dir in baseDirs) {
|
||||||
@ -249,7 +254,7 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isSupportedFile(extension: String): Boolean {
|
private fun isSupportedFile(extension: String): Boolean {
|
||||||
return extension.toLowerCase() in setOf("zip", "rar", "cbr", "cbz", "epub")
|
return extension.toLowerCase() in SUPPORTED_ARCHIVE_TYPES
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFormat(chapter: SChapter): Format {
|
fun getFormat(chapter: SChapter): Format {
|
||||||
@ -283,22 +288,23 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
val format = getFormat(chapter)
|
val format = getFormat(chapter)
|
||||||
return when (format) {
|
return when (format) {
|
||||||
is Format.Directory -> {
|
is Format.Directory -> {
|
||||||
val entry = format.file.listFiles().sortedWith(Comparator<File> { f1, f2 ->
|
val entry = format.file.listFiles()
|
||||||
|
?.sortedWith(Comparator<File> { f1, f2 ->
|
||||||
f1.name.compareToCaseInsensitiveNaturalOrder(f2.name)
|
f1.name.compareToCaseInsensitiveNaturalOrder(f2.name)
|
||||||
})
|
})
|
||||||
.find { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } }
|
?.find { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } }
|
||||||
|
|
||||||
entry?.let { updateCover(context, manga, it.inputStream()) }
|
entry?.let { updateCover(context, manga, it.inputStream()) }
|
||||||
}
|
}
|
||||||
is Format.Zip -> {
|
is Format.Zip -> {
|
||||||
ZipFile(format.file).use { zip ->
|
ZipFile(format.file).use { zip ->
|
||||||
val entry = zip.entries().toList().sortedWith(Comparator<ZipEntry> { f1, f2 ->
|
val entry = zip.entries().toList().sortedWith(Comparator<ZipEntry> { f1, f2 ->
|
||||||
f1.name.compareToCaseInsensitiveNaturalOrder(f2.name)
|
f1.name.compareToCaseInsensitiveNaturalOrder(f2.name)
|
||||||
}).find {
|
}).find {
|
||||||
!it.isDirectory && ImageUtil.isImage(it.name) {
|
!it.isDirectory && ImageUtil.isImage(it.name) {
|
||||||
zip.getInputStream(it)
|
zip.getInputStream(it)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
entry?.let { updateCover(context, manga, zip.getInputStream(it)) }
|
entry?.let { updateCover(context, manga, zip.getInputStream(it)) }
|
||||||
}
|
}
|
||||||
@ -306,12 +312,12 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
is Format.Rar -> {
|
is Format.Rar -> {
|
||||||
Archive(format.file).use { archive ->
|
Archive(format.file).use { archive ->
|
||||||
val entry = archive.fileHeaders.sortedWith(Comparator<FileHeader> { f1, f2 ->
|
val entry = archive.fileHeaders.sortedWith(Comparator<FileHeader> { f1, f2 ->
|
||||||
f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString)
|
f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString)
|
||||||
}).find {
|
}).find {
|
||||||
!it.isDirectory && ImageUtil.isImage(it.fileNameString) {
|
!it.isDirectory && ImageUtil.isImage(it.fileNameString) {
|
||||||
archive.getInputStream(it)
|
archive.getInputStream(it)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
entry?.let { updateCover(context, manga, archive.getInputStream(it)) }
|
entry?.let { updateCover(context, manga, archive.getInputStream(it)) }
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import android.net.Uri
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
@ -117,7 +118,7 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : Bott
|
|||||||
if (track.tracking_url.isBlank()) {
|
if (track.tracking_url.isBlank()) {
|
||||||
activity.toast(R.string.url_not_set_click_again)
|
activity.toast(R.string.url_not_set_click_again)
|
||||||
} else {
|
} else {
|
||||||
activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(track.tracking_url)))
|
activity.startActivity(Intent(Intent.ACTION_VIEW, track.tracking_url.toUri()))
|
||||||
controller.refreshTracker = position
|
controller.refreshTracker = position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import android.widget.FrameLayout
|
|||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.core.net.toUri
|
||||||
import coil.api.loadAny
|
import coil.api.loadAny
|
||||||
import coil.request.CachePolicy
|
import coil.request.CachePolicy
|
||||||
import com.davemorrissey.labs.subscaleview.ImageSource
|
import com.davemorrissey.labs.subscaleview.ImageSource
|
||||||
@ -465,7 +466,7 @@ class PagerPageHolder(
|
|||||||
}
|
}
|
||||||
setText(R.string.open_in_browser)
|
setText(R.string.open_in_browser)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(imageUrl))
|
val intent = Intent(Intent.ACTION_VIEW, imageUrl.toUri())
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import android.widget.LinearLayout
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.widget.AppCompatButton
|
import androidx.appcompat.widget.AppCompatButton
|
||||||
import androidx.appcompat.widget.AppCompatImageView
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
|
import androidx.core.net.toUri
|
||||||
import coil.api.clear
|
import coil.api.clear
|
||||||
import coil.api.loadAny
|
import coil.api.loadAny
|
||||||
import coil.request.CachePolicy
|
import coil.request.CachePolicy
|
||||||
@ -458,7 +459,7 @@ class WebtoonPageHolder(
|
|||||||
}
|
}
|
||||||
setText(R.string.open_in_browser)
|
setText(R.string.open_in_browser)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(imageUrl))
|
val intent = Intent(Intent.ACTION_VIEW, imageUrl.toUri())
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class BiometricActivity : BaseActivity() {
|
|||||||
|
|
||||||
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||||
.setTitle(getString(R.string.unlock_library))
|
.setTitle(getString(R.string.unlock_library))
|
||||||
.setNegativeButtonText(getString(android.R.string.cancel))
|
.setDeviceCredentialAllowed(true)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
biometricPrompt.authenticate(promptInfo)
|
biometricPrompt.authenticate(promptInfo)
|
||||||
|
@ -4,6 +4,7 @@ import android.app.Dialog
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
|
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
|
||||||
@ -58,7 +59,7 @@ class AboutController : SettingsController() {
|
|||||||
val url = "https://tachiyomi.org"
|
val url = "https://tachiyomi.org"
|
||||||
summary = url
|
summary = url
|
||||||
onClick {
|
onClick {
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
val intent = Intent(Intent.ACTION_VIEW, url.toUri())
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,7 +69,7 @@ class AboutController : SettingsController() {
|
|||||||
val url = "https://discord.gg/tachiyomi"
|
val url = "https://discord.gg/tachiyomi"
|
||||||
summary = url
|
summary = url
|
||||||
onClick {
|
onClick {
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
val intent = Intent(Intent.ACTION_VIEW, url.toUri())
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,7 +78,7 @@ class AboutController : SettingsController() {
|
|||||||
val url = "https://github.com/Jays2Kings/tachiyomiJ2K"
|
val url = "https://github.com/Jays2Kings/tachiyomiJ2K"
|
||||||
summary = url
|
summary = url
|
||||||
onClick {
|
onClick {
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
val intent = Intent(Intent.ACTION_VIEW, url.toUri())
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,13 +87,12 @@ class AboutController : SettingsController() {
|
|||||||
titleRes = R.string.whats_new
|
titleRes = R.string.whats_new
|
||||||
onClick {
|
onClick {
|
||||||
val intent = Intent(
|
val intent = Intent(
|
||||||
Intent.ACTION_VIEW, Uri.parse(
|
Intent.ACTION_VIEW,
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
"https://github.com/Jays2Kings/tachiyomiJ2K/commits/master"
|
"https://github.com/Jays2Kings/tachiyomiJ2K/commits/master"
|
||||||
} else {
|
} else {
|
||||||
"https://github.com/Jays2Kings/tachiyomiJ2K/releases/tag/v${BuildConfig.VERSION_NAME}"
|
"https://github.com/Jays2Kings/tachiyomiJ2K/releases/tag/v${BuildConfig.VERSION_NAME}"
|
||||||
}
|
}.toUri()
|
||||||
)
|
|
||||||
)
|
)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import android.os.Bundle
|
|||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -122,7 +123,7 @@ class SettingsAdvancedController : SettingsController() {
|
|||||||
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
|
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
|
||||||
val intent = Intent().apply {
|
val intent = Intent().apply {
|
||||||
action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
||||||
data = Uri.parse("package:$packageName")
|
data = "package:$packageName".toUri()
|
||||||
}
|
}
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,6 +8,7 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.afollestad.materialdialogs.list.listItemsMultiChoice
|
import com.afollestad.materialdialogs.list.listItemsMultiChoice
|
||||||
@ -102,7 +103,7 @@ class SettingsBackupController : SettingsController() {
|
|||||||
|
|
||||||
preferences.backupsDirectory().asObservable()
|
preferences.backupsDirectory().asObservable()
|
||||||
.subscribeUntilDestroy { path ->
|
.subscribeUntilDestroy { path ->
|
||||||
val dir = UniFile.fromUri(context, Uri.parse(path))
|
val dir = UniFile.fromUri(context, path.toUri())
|
||||||
summary = dir.filePath + "/automatic"
|
summary = dir.filePath + "/automatic"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import android.net.Uri
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
||||||
@ -42,7 +43,7 @@ class SettingsDownloadController : SettingsController() {
|
|||||||
|
|
||||||
preferences.downloadsDirectory().asObservable()
|
preferences.downloadsDirectory().asObservable()
|
||||||
.subscribeUntilDestroy { path ->
|
.subscribeUntilDestroy { path ->
|
||||||
val dir = UniFile.fromUri(context, Uri.parse(path))
|
val dir = UniFile.fromUri(context, path.toUri())
|
||||||
summary = dir.filePath ?: path
|
summary = dir.filePath ?: path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import androidx.annotation.StringRes
|
|||||||
import androidx.browser.customtabs.CustomTabsIntent
|
import androidx.browser.customtabs.CustomTabsIntent
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.nononsenseapps.filepicker.FilePickerActivity
|
import com.nononsenseapps.filepicker.FilePickerActivity
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity
|
import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity
|
||||||
@ -223,7 +224,7 @@ fun Context.isServiceRunning(serviceClass: Class<*>): Boolean {
|
|||||||
*/
|
*/
|
||||||
fun Context.openInBrowser(url: String) {
|
fun Context.openInBrowser(url: String) {
|
||||||
try {
|
try {
|
||||||
val parsedUrl = Uri.parse(url)
|
val parsedUrl = url.toUri()
|
||||||
val intent = CustomTabsIntent.Builder()
|
val intent = CustomTabsIntent.Builder()
|
||||||
.setToolbarColor(getResourceColor(R.attr.colorPrimaryVariant))
|
.setToolbarColor(getResourceColor(R.attr.colorPrimaryVariant))
|
||||||
.build()
|
.build()
|
||||||
|
Loading…
Reference in New Issue
Block a user