mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-27 03:27:51 +02:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
4be5f0dab3 | |||
abe1929b49 | |||
68c4116327 | |||
3be9881997 | |||
2e44f29882 | |||
a5520c1936 | |||
112cdd54e3 | |||
b512c67b5d | |||
d8fa7bc9d2 | |||
41397ab41d | |||
c437f1473c | |||
6020cd011d | |||
582bb3e2ca | |||
5c67161dce | |||
c00eaae62b |
@ -38,12 +38,13 @@ android {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 25
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
versionCode 20
|
||||
versionName "0.5.0"
|
||||
versionCode 21
|
||||
versionName "0.5.1"
|
||||
|
||||
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
|
||||
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
|
||||
buildConfigField "String", "BUILD_TIME", "\"${getBuildTime()}\""
|
||||
buildConfigField "boolean", "INCLUDE_UPDATER", "false"
|
||||
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
@ -70,9 +71,11 @@ android {
|
||||
standard {
|
||||
buildConfigField "boolean", "INCLUDE_UPDATER", "true"
|
||||
}
|
||||
|
||||
fdroid {
|
||||
buildConfigField "boolean", "INCLUDE_UPDATER", "false"
|
||||
}
|
||||
dev {
|
||||
minSdkVersion 21
|
||||
resConfigs "en", "xxhdpi"
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +101,7 @@ android {
|
||||
dependencies {
|
||||
|
||||
// Modified dependencies
|
||||
compile 'com.github.inorichi:subsampling-scale-image-view:4255750'
|
||||
compile 'com.github.inorichi:subsampling-scale-image-view:01e5385'
|
||||
compile 'com.github.inorichi:junrar-android:634c1f5'
|
||||
|
||||
// Android support library
|
||||
@ -111,13 +114,13 @@ dependencies {
|
||||
compile "com.android.support:support-annotations:$support_library_version"
|
||||
compile "com.android.support:customtabs:$support_library_version"
|
||||
|
||||
compile 'com.android.support.constraint:constraint-layout:1.0.0'
|
||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
|
||||
compile 'com.android.support:multidex:1.0.1'
|
||||
|
||||
// ReactiveX
|
||||
compile 'io.reactivex:rxandroid:1.2.1'
|
||||
compile 'io.reactivex:rxjava:1.2.6'
|
||||
compile 'io.reactivex:rxjava:1.2.7'
|
||||
compile 'com.jakewharton.rxrelay:rxrelay:1.2.0'
|
||||
compile 'com.f2prateek.rx.preferences:rx-preferences:1.0.2'
|
||||
compile 'com.github.pwittchen:reactivenetwork:0.7.0'
|
||||
@ -150,7 +153,7 @@ dependencies {
|
||||
compile 'org.jsoup:jsoup:1.10.2'
|
||||
|
||||
// Job scheduling
|
||||
compile 'com.evernote:android-job:1.1.6'
|
||||
compile 'com.evernote:android-job:1.1.7'
|
||||
compile 'com.google.android.gms:play-services-gcm:10.2.0'
|
||||
|
||||
// Changelog
|
||||
@ -190,7 +193,7 @@ dependencies {
|
||||
compile 'com.github.inorichi:FlexibleAdapter:93985fe' // v4.2.0 to be removed
|
||||
compile 'com.nononsenseapps:filepicker:2.5.2'
|
||||
compile 'com.github.amulyakhare:TextDrawable:558677e'
|
||||
compile 'com.afollestad.material-dialogs:core:0.9.3.0'
|
||||
compile 'com.afollestad.material-dialogs:core:0.9.4.1'
|
||||
compile 'net.xpece.android:support-preference:1.2.5'
|
||||
compile 'me.zhanghai.android.systemuihelper:library:1.0.0'
|
||||
compile 'de.hdodenhof:circleimageview:2.1.0'
|
||||
@ -209,7 +212,7 @@ dependencies {
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.0.6'
|
||||
ext.kotlin_version = '1.1.1'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.notification.NotificationHandler
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
import eu.kanade.tachiyomi.util.chop
|
||||
import eu.kanade.tachiyomi.util.notificationManager
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* DownloadNotifier is used to show notifications when downloading one or multiple chapters.
|
||||
@ -145,7 +146,8 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
} else {
|
||||
download?.let {
|
||||
val title = it.manga.title.chop(15)
|
||||
val chapter = download.chapter.name.replaceFirst("$title[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
|
||||
val quotedTitle = Pattern.quote(title)
|
||||
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
|
||||
setContentTitle("$title - $chapter".chop(30))
|
||||
setContentText(context.getString(R.string.chapter_downloading_progress)
|
||||
.format(it.downloadedImages, it.pages!!.size))
|
||||
@ -202,7 +204,8 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
// Create notification.
|
||||
with(notification) {
|
||||
val title = download.manga.title.chop(15)
|
||||
val chapter = download.chapter.name.replaceFirst("$title[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
|
||||
val quotedTitle = Pattern.quote(title)
|
||||
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
|
||||
setContentTitle("$title - $chapter".chop(30))
|
||||
setContentText(context.getString(R.string.update_check_notification_download_complete))
|
||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
|
@ -57,6 +57,9 @@ class LibraryUpdateService : Service() {
|
||||
*/
|
||||
val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
/**
|
||||
* Download Manager
|
||||
*/
|
||||
val downloadManager: DownloadManager by injectLazy()
|
||||
|
||||
/**
|
||||
@ -216,7 +219,7 @@ class LibraryUpdateService : Service() {
|
||||
.filter { it.category in categoriesToUpdate }
|
||||
.distinctBy { it.id }
|
||||
else
|
||||
db.getFavoriteMangas().executeAsBlocking().distinctBy { it.id }
|
||||
db.getLibraryMangas().executeAsBlocking().distinctBy { it.id }
|
||||
}
|
||||
|
||||
if (!intent.getBooleanExtra(UPDATE_DETAILS, false) && preferences.updateOnlyNonCompleted()) {
|
||||
@ -238,8 +241,16 @@ class LibraryUpdateService : Service() {
|
||||
fun updateChapterList(mangaToUpdate: List<Manga>): Observable<Manga> {
|
||||
// Initialize the variables holding the progress of the updates.
|
||||
val count = AtomicInteger(0)
|
||||
// List containing new updates
|
||||
val newUpdates = ArrayList<Manga>()
|
||||
// list containing failed updates
|
||||
val failedUpdates = ArrayList<Manga>()
|
||||
// List containing categories that get included in downloads.
|
||||
val categoriesToDownload = preferences.downloadNewCategories().getOrDefault().map(String::toInt)
|
||||
// Boolean to determine if user wants to automatically download new chapters.
|
||||
val downloadNew = preferences.downloadNew().getOrDefault()
|
||||
// Boolean to determine if DownloadManager has downloads
|
||||
var hasDownloads = false
|
||||
|
||||
// Emit each manga and update it sequentially.
|
||||
return Observable.from(mangaToUpdate)
|
||||
@ -254,10 +265,13 @@ class LibraryUpdateService : Service() {
|
||||
Pair(emptyList<Chapter>(), emptyList<Chapter>())
|
||||
}
|
||||
// Filter out mangas without new chapters (or failed).
|
||||
.filter { pair -> pair.first.size > 0 }
|
||||
.filter { pair -> pair.first.isNotEmpty() }
|
||||
.doOnNext {
|
||||
if (preferences.downloadNew()) {
|
||||
downloadChapters(manga, it.first)
|
||||
if (downloadNew) {
|
||||
if (categoriesToDownload.isEmpty() || manga.category in categoriesToDownload) {
|
||||
downloadChapters(manga, it.first)
|
||||
hasDownloads = true
|
||||
}
|
||||
}
|
||||
}
|
||||
// Convert to the manga that contains new chapters.
|
||||
@ -276,10 +290,12 @@ class LibraryUpdateService : Service() {
|
||||
if (newUpdates.isEmpty()) {
|
||||
cancelNotification()
|
||||
} else {
|
||||
if (preferences.downloadNew()) {
|
||||
DownloadService.start(this)
|
||||
}
|
||||
showResultNotification(newUpdates, failedUpdates)
|
||||
if (downloadNew) {
|
||||
if (hasDownloads) {
|
||||
DownloadService.start(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,7 @@ import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.util.deleteIfExists
|
||||
import eu.kanade.tachiyomi.util.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.notificationManager
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import eu.kanade.tachiyomi.util.*
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||
@ -120,7 +117,10 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
dismissNotification(context, notificationId)
|
||||
|
||||
// Delete file
|
||||
File(path).deleteIfExists()
|
||||
val file = File(path)
|
||||
file.deleteIfExists()
|
||||
|
||||
DiskUtil.scanMedia(context, file)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,7 +180,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
val intent = Intent(context, NotificationReceiver::class.java).apply {
|
||||
action = ACTION_RESUME_DOWNLOADS
|
||||
}
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,7 +193,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
val intent = Intent(context, NotificationReceiver::class.java).apply {
|
||||
action = ACTION_CLEAR_DOWNLOADS
|
||||
}
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -208,7 +208,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
action = ACTION_DISMISS_NOTIFICATION
|
||||
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
|
||||
}
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -225,7 +225,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
putExtra(EXTRA_FILE_LOCATION, path)
|
||||
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
|
||||
}
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -242,7 +242,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
putExtra(EXTRA_FILE_LOCATION, path)
|
||||
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
|
||||
}
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,7 +258,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
putExtra(EXTRA_MANGA_ID, manga.id)
|
||||
putExtra(EXTRA_CHAPTER_ID, chapter.id)
|
||||
}
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -271,7 +271,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
val intent = Intent(context, NotificationReceiver::class.java).apply {
|
||||
action = ACTION_CANCEL_LIBRARY_UPDATE
|
||||
}
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
}
|
||||
}
|
@ -93,6 +93,8 @@ class PreferenceKeys(context: Context) {
|
||||
|
||||
val downloadNew = context.getString(R.string.pref_download_new_key)
|
||||
|
||||
val downloadNewCategories = context.getString(R.string.pref_download_new_categories_key)
|
||||
|
||||
fun sourceUsername(sourceId: Long) = "pref_source_username_$sourceId"
|
||||
|
||||
fun sourcePassword(sourceId: Long) = "pref_source_password_$sourceId"
|
||||
|
@ -142,7 +142,9 @@ class PreferencesHelper(val context: Context) {
|
||||
|
||||
fun hiddenCatalogues() = rxPrefs.getStringSet("hidden_catalogues", emptySet())
|
||||
|
||||
fun downloadNew() = prefs.getBoolean(keys.downloadNew, false)
|
||||
fun downloadNew() = rxPrefs.getBoolean(keys.downloadNew, false)
|
||||
|
||||
fun downloadNewCategories() = rxPrefs.getStringSet(keys.downloadNewCategories, emptySet())
|
||||
|
||||
fun lang() = prefs.getString(keys.lang, "")
|
||||
|
||||
|
@ -6,7 +6,6 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
@ -59,14 +58,21 @@ class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.jav
|
||||
fun downloadApk(url: String) {
|
||||
// Show notification download starting.
|
||||
sendInitialBroadcast()
|
||||
// Progress of the download
|
||||
var savedProgress = 0
|
||||
|
||||
val progressListener = object : ProgressListener {
|
||||
|
||||
// Progress of the download
|
||||
var savedProgress = 0
|
||||
|
||||
// Keep track of the last notification sent to avoid posting too many.
|
||||
var lastTick = 0L
|
||||
|
||||
override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
|
||||
val progress = (100 * bytesRead / contentLength).toInt()
|
||||
if (progress > savedProgress) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (progress > savedProgress && currentTime - 200 > lastTick) {
|
||||
savedProgress = progress
|
||||
lastTick = currentTime
|
||||
sendProgressBroadcast(progress)
|
||||
}
|
||||
}
|
||||
@ -112,11 +118,7 @@ class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.jav
|
||||
putExtra(UpdateDownloaderReceiver.EXTRA_ACTION, UpdateDownloaderReceiver.NOTIFICATION_UPDATER_PROGRESS)
|
||||
putExtra(UpdateDownloaderReceiver.EXTRA_PROGRESS, progress)
|
||||
}
|
||||
// Prevents not showing of install notification TODO weird Android N bug. Find out what goes wrong
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N || progress <= 95) {
|
||||
// Show download progress notification.
|
||||
sendLocalBroadcastSync(intent)
|
||||
}
|
||||
sendLocalBroadcastSync(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,7 +10,7 @@ import rx.Subscription
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
fun Call.asObservable(): Observable<Response> {
|
||||
return Observable.create { subscriber ->
|
||||
return Observable.unsafeCreate { subscriber ->
|
||||
// Since Call is a one-shot type, clone it for each new subscriber.
|
||||
val call = clone()
|
||||
|
||||
|
@ -176,8 +176,7 @@ class YamlHttpSource(mappings: Map<*, *>) : HttpSource() {
|
||||
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
// TODO lazy initialization in Kotlin 1.1
|
||||
val document = Jsoup.parse(body, url)
|
||||
val document by lazy { Jsoup.parse(body, url) }
|
||||
|
||||
with(map.pages) {
|
||||
// Capture a list of values where page urls will be resolved.
|
||||
|
@ -1,5 +1,6 @@
|
||||
package eu.kanade.tachiyomi.source.online.english
|
||||
|
||||
import com.squareup.duktape.Duktape
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
@ -114,15 +115,37 @@ class Kissmanga : ParsedHttpSource() {
|
||||
override fun pageListRequest(chapter: SChapter) = POST(baseUrl + chapter.url, headers)
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
//language=RegExp
|
||||
val p = Pattern.compile("""lstImages.push\("(.+?)"""")
|
||||
val m = p.matcher(response.body().string())
|
||||
val body = response.body().string()
|
||||
|
||||
var i = 0
|
||||
while (m.find()) {
|
||||
pages.add(Page(i++, "", m.group(1)))
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
// Kissmanga now encrypts the urls, so we need to execute these two scripts in JS.
|
||||
val ca = client.newCall(GET("$baseUrl/Scripts/ca.js", headers)).execute().body().string()
|
||||
val lo = client.newCall(GET("$baseUrl/Scripts/lo.js", headers)).execute().body().string()
|
||||
|
||||
Duktape.create().use {
|
||||
it.evaluate(ca)
|
||||
it.evaluate(lo)
|
||||
|
||||
// There are two functions in an inline script needed to decrypt the urls. We find and
|
||||
// execute them.
|
||||
var p = Pattern.compile("(.*CryptoJS.*)")
|
||||
var m = p.matcher(body)
|
||||
while (m.find()) {
|
||||
it.evaluate(m.group(1))
|
||||
}
|
||||
|
||||
// Finally find all the urls and decrypt them in JS.
|
||||
p = Pattern.compile("""lstImages.push\((.*)\);""")
|
||||
m = p.matcher(body)
|
||||
|
||||
var i = 0
|
||||
while (m.find()) {
|
||||
val url = it.evaluate(m.group(1)) as String
|
||||
pages.add(Page(i++, "", url))
|
||||
}
|
||||
}
|
||||
|
||||
return pages
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Document
|
||||
@ -27,11 +28,16 @@ class Mangasee : ParsedHttpSource() {
|
||||
|
||||
private val indexPattern = Pattern.compile("-index-(.*?)-")
|
||||
|
||||
private val catalogHeaders = Headers.Builder().apply {
|
||||
add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
||||
add("Host", "mangaseeonline.us")
|
||||
}.build()
|
||||
|
||||
override fun popularMangaSelector() = "div.requested > div.row"
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
val (body, requestUrl) = convertQueryToPost(page, "$baseUrl/search/request.php?sortBy=popularity&sortOrder=descending")
|
||||
return POST(requestUrl, headers, body.build())
|
||||
return POST(requestUrl, catalogHeaders, body.build())
|
||||
}
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
@ -74,7 +80,7 @@ class Mangasee : ParsedHttpSource() {
|
||||
if (genresNo.isNotEmpty()) url.addQueryParameter("genreNo", genresNo.joinToString(","))
|
||||
|
||||
val (body, requestUrl) = convertQueryToPost(page, url.toString())
|
||||
return POST(requestUrl, headers, body.build())
|
||||
return POST(requestUrl, catalogHeaders, body.build())
|
||||
}
|
||||
|
||||
private fun convertQueryToPost(page: Int, url: String): Pair<FormBody.Builder, String> {
|
||||
@ -164,7 +170,7 @@ class Mangasee : ParsedHttpSource() {
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
val url = "http://mangaseeonline.net/home/latest.request.php"
|
||||
val (body, requestUrl) = convertQueryToPost(page, url)
|
||||
return POST(requestUrl, headers, body.build())
|
||||
return POST(requestUrl, catalogHeaders, body.build())
|
||||
}
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package eu.kanade.tachiyomi.ui.base.fragment
|
||||
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v4.app.FragmentActivity
|
||||
import eu.kanade.tachiyomi.ui.base.activity.ActivityMixin
|
||||
|
||||
interface FragmentMixin {
|
||||
@ -13,7 +13,7 @@ interface FragmentMixin {
|
||||
(getActivity() as ActivityMixin).setToolbarTitle(getString(resourceId))
|
||||
}
|
||||
|
||||
fun getActivity(): AppCompatActivity
|
||||
fun getActivity(): FragmentActivity
|
||||
|
||||
fun getString(resource: Int): String
|
||||
}
|
@ -4,6 +4,7 @@ import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.Snackbar
|
||||
import android.support.v4.widget.DrawerLayout
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.*
|
||||
import android.view.*
|
||||
import android.widget.ArrayAdapter
|
||||
@ -155,7 +156,7 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(),
|
||||
setupRecycler()
|
||||
|
||||
// Create toolbar spinner
|
||||
val themedContext = activity.supportActionBar?.themedContext ?: activity
|
||||
val themedContext = (activity as AppCompatActivity).supportActionBar?.themedContext ?: activity
|
||||
|
||||
val spinnerAdapter = ArrayAdapter(themedContext,
|
||||
android.R.layout.simple_spinner_item, presenter.sources)
|
||||
|
@ -9,6 +9,7 @@ import android.support.design.widget.TabLayout
|
||||
import android.support.v4.graphics.drawable.DrawableCompat
|
||||
import android.support.v4.view.ViewPager
|
||||
import android.support.v4.widget.DrawerLayout
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.view.ActionMode
|
||||
import android.support.v7.widget.SearchView
|
||||
import android.view.*
|
||||
@ -356,7 +357,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
||||
*/
|
||||
fun createActionModeIfNeeded() {
|
||||
if (actionMode == null) {
|
||||
actionMode = activity.startSupportActionMode(this)
|
||||
actionMode = (activity as AppCompatActivity).startSupportActionMode(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,12 +177,9 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
||||
private fun applySort(map: Map<Int, List<Manga>>): Map<Int, List<Manga>> {
|
||||
val sortingMode = preferences.librarySortingMode().getOrDefault()
|
||||
|
||||
// TODO lazy initialization in kotlin 1.1
|
||||
var lastReadManga: Map<Long, Int>? = null
|
||||
if (sortingMode == LibrarySort.LAST_READ) {
|
||||
val lastReadManga by lazy {
|
||||
var counter = 0
|
||||
lastReadManga = db.getLastReadManga().executeAsBlocking()
|
||||
.associate { it.id!! to counter++ }
|
||||
db.getLastReadManga().executeAsBlocking().associate { it.id!! to counter++ }
|
||||
}
|
||||
|
||||
val sortFn: (Manga, Manga) -> Int = { manga1, manga2 ->
|
||||
@ -190,8 +187,8 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
||||
LibrarySort.ALPHA -> manga1.title.compareTo(manga2.title)
|
||||
LibrarySort.LAST_READ -> {
|
||||
// Get index of manga, set equal to list if size unknown.
|
||||
val manga1LastRead = lastReadManga!![manga1.id!!] ?: lastReadManga!!.size
|
||||
val manga2LastRead = lastReadManga!![manga2.id!!] ?: lastReadManga!!.size
|
||||
val manga1LastRead = lastReadManga[manga1.id!!] ?: lastReadManga.size
|
||||
val manga2LastRead = lastReadManga[manga2.id!!] ?: lastReadManga.size
|
||||
manga1LastRead.compareTo(manga2LastRead)
|
||||
}
|
||||
LibrarySort.LAST_UPDATED -> manga2.last_update.compareTo(manga1.last_update)
|
||||
|
@ -1,128 +1,116 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.PopupMenu
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.util.getResourceColor
|
||||
import kotlinx.android.synthetic.main.item_chapter.view.*
|
||||
import java.text.DateFormat
|
||||
import java.text.DecimalFormat
|
||||
import java.text.DecimalFormatSymbols
|
||||
import java.util.*
|
||||
|
||||
class ChaptersHolder(
|
||||
private val view: View,
|
||||
private val adapter: ChaptersAdapter,
|
||||
listener: FlexibleViewHolder.OnListItemClickListener)
|
||||
: FlexibleViewHolder(view, adapter, listener) {
|
||||
|
||||
private val readColor = view.context.getResourceColor(android.R.attr.textColorHint)
|
||||
private val unreadColor = view.context.getResourceColor(android.R.attr.textColorPrimary)
|
||||
private val bookmarkedColor = view.context.getResourceColor(R.attr.colorAccent)
|
||||
private val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols().apply { decimalSeparator = '.' })
|
||||
private val df = DateFormat.getDateInstance(DateFormat.SHORT)
|
||||
|
||||
private var item: ChapterModel? = null
|
||||
|
||||
init {
|
||||
// We need to post a Runnable to show the popup to make sure that the PopupMenu is
|
||||
// correctly positioned. The reason being that the view may change position before the
|
||||
// PopupMenu is shown.
|
||||
view.chapter_menu.setOnClickListener { it.post { showPopupMenu(it) } }
|
||||
}
|
||||
|
||||
fun onSetValues(chapter: ChapterModel, manga: Manga?) = with(view) {
|
||||
item = chapter
|
||||
|
||||
chapter_title.text = when (manga?.displayMode) {
|
||||
Manga.DISPLAY_NUMBER -> {
|
||||
val formattedNumber = decimalFormat.format(chapter.chapter_number.toDouble())
|
||||
context.getString(R.string.display_mode_chapter, formattedNumber)
|
||||
}
|
||||
else -> chapter.name
|
||||
}
|
||||
|
||||
// Set correct text color
|
||||
chapter_title.setTextColor(if (chapter.read) readColor else unreadColor)
|
||||
if (chapter.bookmark) chapter_title.setTextColor(bookmarkedColor)
|
||||
|
||||
if (chapter.date_upload > 0) {
|
||||
chapter_date.text = df.format(Date(chapter.date_upload))
|
||||
chapter_date.setTextColor(if (chapter.read) readColor else unreadColor)
|
||||
} else {
|
||||
chapter_date.text = ""
|
||||
}
|
||||
|
||||
chapter_pages.text = if (!chapter.read && chapter.last_page_read > 0) {
|
||||
context.getString(R.string.chapter_progress, chapter.last_page_read + 1)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
notifyStatus(chapter.status)
|
||||
}
|
||||
|
||||
fun notifyStatus(status: Int) = with(view.download_text) {
|
||||
when (status) {
|
||||
Download.QUEUE -> setText(R.string.chapter_queued)
|
||||
Download.DOWNLOADING -> setText(R.string.chapter_downloading)
|
||||
Download.DOWNLOADED -> setText(R.string.chapter_downloaded)
|
||||
Download.ERROR -> setText(R.string.chapter_error)
|
||||
else -> text = ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun showPopupMenu(view: View) = item?.let { chapter ->
|
||||
// Create a PopupMenu, giving it the clicked view for an anchor
|
||||
val popup = PopupMenu(view.context, view)
|
||||
|
||||
// Inflate our menu resource into the PopupMenu's Menu
|
||||
popup.menuInflater.inflate(R.menu.chapter_single, popup.menu)
|
||||
|
||||
// Hide download and show delete if the chapter is downloaded
|
||||
if (chapter.isDownloaded) {
|
||||
popup.menu.findItem(R.id.action_download).isVisible = false
|
||||
popup.menu.findItem(R.id.action_delete).isVisible = true
|
||||
}
|
||||
|
||||
// Hide bookmark if bookmark
|
||||
popup.menu.findItem(R.id.action_bookmark).isVisible = !chapter.bookmark
|
||||
popup.menu.findItem(R.id.action_remove_bookmark).isVisible = chapter.bookmark
|
||||
|
||||
// Hide mark as unread when the chapter is unread
|
||||
if (!chapter.read && chapter.last_page_read == 0) {
|
||||
popup.menu.findItem(R.id.action_mark_as_unread).isVisible = false
|
||||
}
|
||||
|
||||
// Hide mark as read when the chapter is read
|
||||
if (chapter.read) {
|
||||
popup.menu.findItem(R.id.action_mark_as_read).isVisible = false
|
||||
}
|
||||
|
||||
// Set a listener so we are notified if a menu item is clicked
|
||||
popup.setOnMenuItemClickListener { menuItem ->
|
||||
val chapterList = listOf(chapter)
|
||||
|
||||
with(adapter.fragment) {
|
||||
when (menuItem.itemId) {
|
||||
R.id.action_download -> downloadChapters(chapterList)
|
||||
R.id.action_bookmark -> bookmarkChapters(chapterList, true)
|
||||
R.id.action_remove_bookmark -> bookmarkChapters(chapterList, false)
|
||||
R.id.action_delete -> deleteChapters(chapterList)
|
||||
R.id.action_mark_as_read -> markAsRead(chapterList)
|
||||
R.id.action_mark_as_unread -> markAsUnread(chapterList)
|
||||
R.id.action_mark_previous_as_read -> markPreviousAsRead(chapter)
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
// Finally show the PopupMenu
|
||||
popup.show()
|
||||
}
|
||||
|
||||
}
|
||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.PopupMenu
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.util.getResourceColor
|
||||
import kotlinx.android.synthetic.main.item_chapter.view.*
|
||||
import java.text.DateFormat
|
||||
import java.text.DecimalFormat
|
||||
import java.text.DecimalFormatSymbols
|
||||
import java.util.*
|
||||
|
||||
class ChapterHolder(
|
||||
private val view: View,
|
||||
private val adapter: ChaptersAdapter)
|
||||
: FlexibleViewHolder(view, adapter) {
|
||||
|
||||
private val readColor = view.context.getResourceColor(android.R.attr.textColorHint)
|
||||
private val unreadColor = view.context.getResourceColor(android.R.attr.textColorPrimary)
|
||||
private val bookmarkedColor = view.context.getResourceColor(R.attr.colorAccent)
|
||||
private val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols().apply { decimalSeparator = '.' })
|
||||
private val df = DateFormat.getDateInstance(DateFormat.SHORT)
|
||||
|
||||
init {
|
||||
// We need to post a Runnable to show the popup to make sure that the PopupMenu is
|
||||
// correctly positioned. The reason being that the view may change position before the
|
||||
// PopupMenu is shown.
|
||||
view.chapter_menu.setOnClickListener { it.post { showPopupMenu(it) } }
|
||||
}
|
||||
|
||||
fun bind(item: ChapterItem, manga: Manga) = with(view) {
|
||||
val chapter = item.chapter
|
||||
|
||||
chapter_title.text = when (manga.displayMode) {
|
||||
Manga.DISPLAY_NUMBER -> {
|
||||
val formattedNumber = decimalFormat.format(chapter.chapter_number.toDouble())
|
||||
context.getString(R.string.display_mode_chapter, formattedNumber)
|
||||
}
|
||||
else -> chapter.name
|
||||
}
|
||||
|
||||
// Set correct text color
|
||||
chapter_title.setTextColor(if (chapter.read) readColor else unreadColor)
|
||||
if (chapter.bookmark) chapter_title.setTextColor(bookmarkedColor)
|
||||
|
||||
if (chapter.date_upload > 0) {
|
||||
chapter_date.text = df.format(Date(chapter.date_upload))
|
||||
chapter_date.setTextColor(if (chapter.read) readColor else unreadColor)
|
||||
} else {
|
||||
chapter_date.text = ""
|
||||
}
|
||||
|
||||
chapter_pages.text = if (!chapter.read && chapter.last_page_read > 0) {
|
||||
context.getString(R.string.chapter_progress, chapter.last_page_read + 1)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
notifyStatus(item.status)
|
||||
}
|
||||
|
||||
fun notifyStatus(status: Int) = with(view.download_text) {
|
||||
when (status) {
|
||||
Download.QUEUE -> setText(R.string.chapter_queued)
|
||||
Download.DOWNLOADING -> setText(R.string.chapter_downloading)
|
||||
Download.DOWNLOADED -> setText(R.string.chapter_downloaded)
|
||||
Download.ERROR -> setText(R.string.chapter_error)
|
||||
else -> text = ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun showPopupMenu(view: View) {
|
||||
val item = adapter.getItem(adapterPosition) ?: return
|
||||
|
||||
// Create a PopupMenu, giving it the clicked view for an anchor
|
||||
val popup = PopupMenu(view.context, view)
|
||||
|
||||
// Inflate our menu resource into the PopupMenu's Menu
|
||||
popup.menuInflater.inflate(R.menu.chapter_single, popup.menu)
|
||||
|
||||
val chapter = item.chapter
|
||||
|
||||
// Hide download and show delete if the chapter is downloaded
|
||||
if (item.isDownloaded) {
|
||||
popup.menu.findItem(R.id.action_download).isVisible = false
|
||||
popup.menu.findItem(R.id.action_delete).isVisible = true
|
||||
}
|
||||
|
||||
// Hide bookmark if bookmark
|
||||
popup.menu.findItem(R.id.action_bookmark).isVisible = !chapter.bookmark
|
||||
popup.menu.findItem(R.id.action_remove_bookmark).isVisible = chapter.bookmark
|
||||
|
||||
// Hide mark as unread when the chapter is unread
|
||||
if (!chapter.read && chapter.last_page_read == 0) {
|
||||
popup.menu.findItem(R.id.action_mark_as_unread).isVisible = false
|
||||
}
|
||||
|
||||
// Hide mark as read when the chapter is read
|
||||
if (chapter.read) {
|
||||
popup.menu.findItem(R.id.action_mark_as_read).isVisible = false
|
||||
}
|
||||
|
||||
// Set a listener so we are notified if a menu item is clicked
|
||||
popup.setOnMenuItemClickListener { menuItem ->
|
||||
adapter.menuItemListener(adapterPosition, menuItem)
|
||||
true
|
||||
}
|
||||
|
||||
// Finally show the PopupMenu
|
||||
popup.show()
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
|
||||
class ChapterItem(val chapter: Chapter, val manga: Manga) : AbstractFlexibleItem<ChapterHolder>(),
|
||||
Chapter by chapter {
|
||||
|
||||
private var _status: Int = 0
|
||||
|
||||
var status: Int
|
||||
get() = download?.status ?: _status
|
||||
set(value) { _status = value }
|
||||
|
||||
@Transient var download: Download? = null
|
||||
|
||||
val isDownloaded: Boolean
|
||||
get() = status == Download.DOWNLOADED
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.item_chapter
|
||||
}
|
||||
|
||||
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): ChapterHolder {
|
||||
return ChapterHolder(inflater.inflate(layoutRes, parent, false), adapter as ChaptersAdapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: ChapterHolder, position: Int, payloads: List<Any?>?) {
|
||||
holder.bind(this, manga)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is ChapterItem) {
|
||||
return chapter.id!! == other.chapter.id!!
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return chapter.id!!.hashCode()
|
||||
}
|
||||
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
|
||||
class ChapterModel(c: Chapter) : Chapter by c {
|
||||
|
||||
private var _status: Int = 0
|
||||
|
||||
var status: Int
|
||||
get() = download?.status ?: _status
|
||||
set(value) { _status = value }
|
||||
|
||||
@Transient var download: Download? = null
|
||||
|
||||
val isDownloaded: Boolean
|
||||
get() = status == Download.DOWNLOADED
|
||||
|
||||
}
|
@ -1,42 +1,19 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||
|
||||
import android.view.ViewGroup
|
||||
import eu.davidea.flexibleadapter4.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.inflate
|
||||
import android.view.MenuItem
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
|
||||
class ChaptersAdapter(val fragment: ChaptersFragment) : FlexibleAdapter<ChaptersHolder, ChapterModel>() {
|
||||
class ChaptersAdapter(val fragment: ChaptersFragment) : FlexibleAdapter<ChapterItem>(null, fragment, true) {
|
||||
|
||||
init {
|
||||
setHasStableIds(true)
|
||||
var items: List<ChapterItem> = emptyList()
|
||||
|
||||
val menuItemListener: (Int, MenuItem) -> Unit = { position, item ->
|
||||
fragment.onItemMenuClick(position, item)
|
||||
}
|
||||
|
||||
var items: List<ChapterModel>
|
||||
get() = mItems
|
||||
set(value) {
|
||||
mItems = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun updateDataSet(param: String) {
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChaptersHolder {
|
||||
val v = parent.inflate(R.layout.item_chapter)
|
||||
return ChaptersHolder(v, this, fragment)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ChaptersHolder, position: Int) {
|
||||
val chapter = getItem(position)
|
||||
val manga = fragment.presenter.manga
|
||||
holder.onSetValues(chapter, manga)
|
||||
|
||||
//When user scrolls this bind the correct selection status
|
||||
holder.itemView.isActivated = isSelected(position)
|
||||
}
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
return mItems[position].id!!
|
||||
override fun updateDataSet(items: List<ChapterItem>) {
|
||||
this.items = items
|
||||
super.updateDataSet(items.toList())
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,17 +6,17 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.Snackbar
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.view.ActionMode
|
||||
import android.support.v7.widget.DividerItemDecoration
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.view.*
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import eu.davidea.flexibleadapter4.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaActivity
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
@ -29,7 +29,10 @@ import nucleus.factory.RequiresPresenter
|
||||
import timber.log.Timber
|
||||
|
||||
@RequiresPresenter(ChaptersPresenter::class)
|
||||
class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener {
|
||||
class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(),
|
||||
ActionMode.Callback,
|
||||
FlexibleAdapter.OnItemClickListener,
|
||||
FlexibleAdapter.OnItemLongClickListener {
|
||||
|
||||
companion object {
|
||||
/**
|
||||
@ -70,38 +73,31 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
recycler.layoutManager = LinearLayoutManager(activity)
|
||||
recycler.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
|
||||
recycler.setHasFixedSize(true)
|
||||
// TODO enable in a future commit
|
||||
// adapter.setFastScroller(fast_scroller, context.getResourceColor(R.attr.colorAccent))
|
||||
// adapter.toggleFastScroller()
|
||||
|
||||
swipe_refresh.setOnRefreshListener { fetchChapters() }
|
||||
|
||||
fab.setOnClickListener {
|
||||
val chapter = presenter.getNextUnreadChapter()
|
||||
if (chapter != null) {
|
||||
val item = presenter.getNextUnreadChapter()
|
||||
if (item != null) {
|
||||
// Create animation listener
|
||||
val revealAnimationListener: Animator.AnimatorListener = object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationStart(animation: Animator?) {
|
||||
openChapter(chapter, true)
|
||||
openChapter(item.chapter, true)
|
||||
}
|
||||
}
|
||||
|
||||
// Get coordinates and start animation
|
||||
val coordinates = fab.getCoordinates()
|
||||
if (!reveal_view.showRevealEffect(coordinates.x, coordinates.y, revealAnimationListener)) {
|
||||
openChapter(chapter)
|
||||
openChapter(item.chapter)
|
||||
}
|
||||
} else {
|
||||
context.toast(R.string.no_next_chapter)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
// Stop recycler's scrolling when onPause is called. If the activity is finishing
|
||||
// the presenter will be destroyed, and it could cause NPE
|
||||
// https://github.com/inorichi/tachiyomi/issues/159
|
||||
recycler.stopScroll()
|
||||
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@ -172,19 +168,20 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
return true
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun onNextManga(manga: Manga) {
|
||||
// Set initial values
|
||||
activity.supportInvalidateOptionsMenu()
|
||||
}
|
||||
|
||||
fun onNextChapters(chapters: List<ChapterModel>) {
|
||||
fun onNextChapters(chapters: List<ChapterItem>) {
|
||||
// If the list is empty, fetch chapters from source if the conditions are met
|
||||
// We use presenter chapters instead because they are always unfiltered
|
||||
if (presenter.chapters.isEmpty())
|
||||
initialFetchChapters()
|
||||
|
||||
destroyActionModeIfNeeded()
|
||||
adapter.items = chapters
|
||||
adapter.updateDataSet(chapters)
|
||||
}
|
||||
|
||||
private fun initialFetchChapters() {
|
||||
@ -229,7 +226,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
.title(R.string.action_display_mode)
|
||||
.items(modes.map { getString(it) })
|
||||
.itemsIds(ids)
|
||||
.itemsCallbackSingleChoice(selectedIndex) { dialog, itemView, which, text ->
|
||||
.itemsCallbackSingleChoice(selectedIndex) { _, itemView, _, _ ->
|
||||
// Save the new display mode
|
||||
presenter.setDisplayMode(itemView.id)
|
||||
// Refresh ui
|
||||
@ -249,7 +246,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
.title(R.string.sorting_mode)
|
||||
.items(modes.map { getString(it) })
|
||||
.itemsIds(ids)
|
||||
.itemsCallbackSingleChoice(selectedIndex) { dialog, itemView, which, text ->
|
||||
.itemsCallbackSingleChoice(selectedIndex) { _, itemView, _, _ ->
|
||||
// Save the new sorting mode
|
||||
presenter.setSorting(itemView.id)
|
||||
true
|
||||
@ -266,7 +263,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
.title(R.string.manga_download)
|
||||
.negativeText(android.R.string.cancel)
|
||||
.items(modes.map { getString(it) })
|
||||
.itemsCallback { dialog, view, i, charSequence ->
|
||||
.itemsCallback { _, _, i, _ ->
|
||||
|
||||
fun getUnreadChaptersSorted() = presenter.chapters
|
||||
.filter { !it.read && it.status == Download.NOT_DOWNLOADED }
|
||||
@ -298,8 +295,8 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
getHolder(download.chapter)?.notifyStatus(download.status)
|
||||
}
|
||||
|
||||
private fun getHolder(chapter: Chapter): ChaptersHolder? {
|
||||
return recycler.findViewHolderForItemId(chapter.id!!) as? ChaptersHolder
|
||||
private fun getHolder(chapter: Chapter): ChapterHolder? {
|
||||
return recycler.findViewHolderForItemId(chapter.id!!) as? ChapterHolder
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
@ -323,7 +320,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
.content(R.string.confirm_delete_chapters)
|
||||
.positiveText(android.R.string.yes)
|
||||
.negativeText(android.R.string.no)
|
||||
.onPositive { dialog, action -> deleteChapters(getSelectedChapters()) }
|
||||
.onPositive { _, _ -> deleteChapters(getSelectedChapters()) }
|
||||
.show()
|
||||
}
|
||||
else -> return false
|
||||
@ -337,8 +334,8 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
actionMode = null
|
||||
}
|
||||
|
||||
fun getSelectedChapters(): List<ChapterModel> {
|
||||
return adapter.selectedItems.map { adapter.getItem(it) }
|
||||
fun getSelectedChapters(): List<ChapterItem> {
|
||||
return adapter.selectedPositions.map { adapter.getItem(it) }
|
||||
}
|
||||
|
||||
fun destroyActionModeIfNeeded() {
|
||||
@ -350,18 +347,18 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
setContextTitle(adapter.selectedItemCount)
|
||||
}
|
||||
|
||||
fun markAsRead(chapters: List<ChapterModel>) {
|
||||
fun markAsRead(chapters: List<ChapterItem>) {
|
||||
presenter.markChaptersRead(chapters, true)
|
||||
if (presenter.preferences.removeAfterMarkedAsRead()) {
|
||||
deleteChapters(chapters)
|
||||
}
|
||||
}
|
||||
|
||||
fun markAsUnread(chapters: List<ChapterModel>) {
|
||||
fun markAsUnread(chapters: List<ChapterItem>) {
|
||||
presenter.markChaptersRead(chapters, false)
|
||||
}
|
||||
|
||||
fun markPreviousAsRead(chapter: ChapterModel) {
|
||||
fun markPreviousAsRead(chapter: ChapterItem) {
|
||||
val chapters = if (presenter.sortDescending()) adapter.items.reversed() else adapter.items
|
||||
val chapterPos = chapters.indexOf(chapter)
|
||||
if (chapterPos != -1) {
|
||||
@ -369,7 +366,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadChapters(chapters: List<ChapterModel>) {
|
||||
fun downloadChapters(chapters: List<ChapterItem>) {
|
||||
destroyActionModeIfNeeded()
|
||||
presenter.downloadChapters(chapters)
|
||||
if (!presenter.manga.favorite){
|
||||
@ -381,12 +378,12 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
}
|
||||
}
|
||||
|
||||
fun bookmarkChapters(chapters: List<ChapterModel>, bookmarked: Boolean) {
|
||||
fun bookmarkChapters(chapters: List<ChapterItem>, bookmarked: Boolean) {
|
||||
destroyActionModeIfNeeded()
|
||||
presenter.bookmarkChapters(chapters, bookmarked)
|
||||
}
|
||||
|
||||
fun deleteChapters(chapters: List<ChapterModel>) {
|
||||
fun deleteChapters(chapters: List<ChapterItem>) {
|
||||
destroyActionModeIfNeeded()
|
||||
DeletingChaptersDialog().show(childFragmentManager, DeletingChaptersDialog.TAG)
|
||||
presenter.deleteChapters(chapters)
|
||||
@ -407,26 +404,40 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
|
||||
?.dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
override fun onListItemClick(position: Int): Boolean {
|
||||
override fun onItemClick(position: Int): Boolean {
|
||||
val item = adapter.getItem(position) ?: return false
|
||||
if (actionMode != null && adapter.mode == FlexibleAdapter.MODE_MULTI) {
|
||||
toggleSelection(position)
|
||||
return true
|
||||
} else {
|
||||
openChapter(item)
|
||||
openChapter(item.chapter)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onListItemLongClick(position: Int) {
|
||||
override fun onItemLongClick(position: Int) {
|
||||
if (actionMode == null)
|
||||
actionMode = activity.startSupportActionMode(this)
|
||||
actionMode = (activity as AppCompatActivity).startSupportActionMode(this)
|
||||
|
||||
toggleSelection(position)
|
||||
}
|
||||
|
||||
fun onItemMenuClick(position: Int, item: MenuItem) {
|
||||
val chapter = adapter.getItem(position)?.let { listOf(it) } ?: return
|
||||
|
||||
when (item.itemId) {
|
||||
R.id.action_download -> downloadChapters(chapter)
|
||||
R.id.action_bookmark -> bookmarkChapters(chapter, true)
|
||||
R.id.action_remove_bookmark -> bookmarkChapters(chapter, false)
|
||||
R.id.action_delete -> deleteChapters(chapter)
|
||||
R.id.action_mark_as_read -> markAsRead(chapter)
|
||||
R.id.action_mark_as_unread -> markAsUnread(chapter)
|
||||
R.id.action_mark_previous_as_read -> markPreviousAsRead(chapter[0])
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleSelection(position: Int) {
|
||||
adapter.toggleSelection(position, false)
|
||||
adapter.toggleSelection(position)
|
||||
|
||||
val count = adapter.selectedItemCount
|
||||
if (count == 0) {
|
||||
|
@ -65,14 +65,14 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
/**
|
||||
* List of chapters of the manga. It's always unfiltered and unsorted.
|
||||
*/
|
||||
var chapters: List<ChapterModel> = emptyList()
|
||||
var chapters: List<ChapterItem> = emptyList()
|
||||
private set
|
||||
|
||||
/**
|
||||
* Subject of list of chapters to allow updating the view without going to DB.
|
||||
*/
|
||||
val chaptersRelay: PublishRelay<List<ChapterModel>>
|
||||
by lazy { PublishRelay.create<List<ChapterModel>>() }
|
||||
val chaptersRelay: PublishRelay<List<ChapterItem>>
|
||||
by lazy { PublishRelay.create<List<ChapterItem>>() }
|
||||
|
||||
/**
|
||||
* Whether the chapter list has been requested to the source.
|
||||
@ -103,7 +103,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
chaptersRelay.flatMap { applyChapterFilters(it) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeLatestCache(ChaptersFragment::onNextChapters,
|
||||
{ view, error -> Timber.e(error) })
|
||||
{ _, error -> Timber.e(error) })
|
||||
|
||||
// Add the subscription that retrieves the chapters from the database, keeps subscribed to
|
||||
// changes, and sends the list of chapters to the relay.
|
||||
@ -135,15 +135,15 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
.filter { download -> download.manga.id == manga.id }
|
||||
.doOnNext { onDownloadStatusChange(it) }
|
||||
.subscribeLatestCache(ChaptersFragment::onChapterStatusChange,
|
||||
{ view, error -> Timber.e(error) })
|
||||
{ _, error -> Timber.e(error) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a chapter from the database to an extended model, allowing to store new fields.
|
||||
*/
|
||||
private fun Chapter.toModel(): ChapterModel {
|
||||
private fun Chapter.toModel(): ChapterItem {
|
||||
// Create the model object.
|
||||
val model = ChapterModel(this)
|
||||
val model = ChapterItem(this, manga)
|
||||
|
||||
// Find an active download for this chapter.
|
||||
val download = downloadManager.queue.find { it.chapter.id == id }
|
||||
@ -160,7 +160,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
*
|
||||
* @param chapters the list of chapter from the database.
|
||||
*/
|
||||
private fun setDownloadedChapters(chapters: List<ChapterModel>) {
|
||||
private fun setDownloadedChapters(chapters: List<ChapterItem>) {
|
||||
val files = downloadManager.findMangaDir(source, manga)?.listFiles() ?: return
|
||||
val cached = mutableMapOf<Chapter, String>()
|
||||
files.mapNotNull { it.name }
|
||||
@ -181,7 +181,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map { syncChaptersWithSource(db, it, manga, source) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst({ view, chapters ->
|
||||
.subscribeFirst({ view, _ ->
|
||||
view.onFetchChaptersDone()
|
||||
}, ChaptersFragment::onFetchChaptersError)
|
||||
}
|
||||
@ -198,7 +198,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
* @param chapters the list of chapters from the database
|
||||
* @return an observable of the list of chapters filtered and sorted.
|
||||
*/
|
||||
private fun applyChapterFilters(chapters: List<ChapterModel>): Observable<List<ChapterModel>> {
|
||||
private fun applyChapterFilters(chapters: List<ChapterItem>): Observable<List<ChapterItem>> {
|
||||
var observable = Observable.from(chapters).subscribeOn(Schedulers.io())
|
||||
if (onlyUnread()) {
|
||||
observable = observable.filter { !it.read }
|
||||
@ -248,7 +248,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
/**
|
||||
* Returns the next unread chapter or null if everything is read.
|
||||
*/
|
||||
fun getNextUnreadChapter(): ChapterModel? {
|
||||
fun getNextUnreadChapter(): ChapterItem? {
|
||||
return chapters.sortedByDescending { it.source_order }.find { !it.read }
|
||||
}
|
||||
|
||||
@ -257,7 +257,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
* @param selectedChapters the list of selected chapters.
|
||||
* @param read whether to mark chapters as read or unread.
|
||||
*/
|
||||
fun markChaptersRead(selectedChapters: List<ChapterModel>, read: Boolean) {
|
||||
fun markChaptersRead(selectedChapters: List<ChapterItem>, read: Boolean) {
|
||||
Observable.from(selectedChapters)
|
||||
.doOnNext { chapter ->
|
||||
chapter.read = read
|
||||
@ -275,7 +275,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
* Downloads the given list of chapters with the manager.
|
||||
* @param chapters the list of chapters to download.
|
||||
*/
|
||||
fun downloadChapters(chapters: List<ChapterModel>) {
|
||||
fun downloadChapters(chapters: List<ChapterItem>) {
|
||||
DownloadService.start(context)
|
||||
downloadManager.downloadChapters(manga, chapters)
|
||||
}
|
||||
@ -284,7 +284,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
* Bookmarks the given list of chapters.
|
||||
* @param selectedChapters the list of chapters to bookmark.
|
||||
*/
|
||||
fun bookmarkChapters(selectedChapters: List<ChapterModel>, bookmarked: Boolean) {
|
||||
fun bookmarkChapters(selectedChapters: List<ChapterItem>, bookmarked: Boolean) {
|
||||
Observable.from(selectedChapters)
|
||||
.doOnNext { chapter ->
|
||||
chapter.bookmark = bookmarked
|
||||
@ -299,14 +299,14 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
* Deletes the given list of chapter.
|
||||
* @param chapters the list of chapters to delete.
|
||||
*/
|
||||
fun deleteChapters(chapters: List<ChapterModel>) {
|
||||
fun deleteChapters(chapters: List<ChapterItem>) {
|
||||
Observable.from(chapters)
|
||||
.doOnNext { deleteChapter(it) }
|
||||
.toList()
|
||||
.doOnNext { if (onlyDownloaded()) refreshChapters() }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst({ view, result ->
|
||||
.subscribeFirst({ view, _ ->
|
||||
view.onChaptersDeleted()
|
||||
}, ChaptersFragment::onChaptersDeletedError)
|
||||
}
|
||||
@ -315,7 +315,7 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
|
||||
* Deletes a chapter from disk. This method is called in a background thread.
|
||||
* @param chapter the chapter to delete.
|
||||
*/
|
||||
private fun deleteChapter(chapter: ChapterModel) {
|
||||
private fun deleteChapter(chapter: ChapterItem) {
|
||||
downloadManager.queue.remove(chapter)
|
||||
downloadManager.deleteChapter(source, manga, chapter)
|
||||
chapter.status = Download.NOT_DOWNLOADED
|
||||
|
@ -607,13 +607,17 @@ class ReaderPresenter : BasePresenter<ReaderActivity>() {
|
||||
}
|
||||
}
|
||||
|
||||
DiskUtil.scanMedia(context, destFile)
|
||||
|
||||
imageNotifier.onComplete(destFile)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe({},
|
||||
{ error ->
|
||||
Timber.e(error)
|
||||
imageNotifier.onError(error.message)
|
||||
})
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
context.toast(R.string.picture_saved)
|
||||
}, { error ->
|
||||
Timber.e(error)
|
||||
imageNotifier.onError(error.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +230,10 @@ abstract class PagerReader : BaseReader() {
|
||||
*/
|
||||
protected fun setPagesOnAdapter() {
|
||||
if (pages.isNotEmpty()) {
|
||||
// Prevent a wrong active page when changing chapters with the navigation buttons.
|
||||
val currPage = currentPage
|
||||
adapter.pages = pages
|
||||
currentPage = currPage
|
||||
if (currentPage == pager.currentItem) {
|
||||
onPageChanged(currentPage)
|
||||
} else {
|
||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.recent_updates
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.view.ActionMode
|
||||
import android.support.v7.widget.DividerItemDecoration
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
@ -142,7 +143,7 @@ class RecentChaptersFragment:
|
||||
*/
|
||||
override fun onItemLongClick(position: Int) {
|
||||
if (actionMode == null)
|
||||
actionMode = activity.startSupportActionMode(this)
|
||||
actionMode = (activity as AppCompatActivity).startSupportActionMode(this)
|
||||
|
||||
toggleSelection(position)
|
||||
}
|
||||
|
@ -19,10 +19,12 @@ import com.nononsenseapps.filepicker.FilePickerActivity
|
||||
import com.nononsenseapps.filepicker.FilePickerFragment
|
||||
import com.nononsenseapps.filepicker.LogicHandler
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.util.inflate
|
||||
import eu.kanade.tachiyomi.util.plusAssign
|
||||
import net.xpece.android.support.preference.MultiSelectListPreference
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
|
||||
@ -41,8 +43,12 @@ class SettingsDownloadsFragment : SettingsFragment() {
|
||||
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
|
||||
val downloadDirPref: Preference by bindPref(R.string.pref_download_directory_key)
|
||||
|
||||
val downloadCategory: MultiSelectListPreference by bindPref(R.string.pref_download_new_categories_key)
|
||||
|
||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
||||
super.onViewCreated(view, savedState)
|
||||
|
||||
@ -92,6 +98,29 @@ class SettingsDownloadsFragment : SettingsFragment() {
|
||||
dir.createFile(".nomedia")
|
||||
}
|
||||
}
|
||||
|
||||
subscriptions += preferences.downloadNew().asObservable()
|
||||
.subscribe { downloadCategory.isVisible = it }
|
||||
|
||||
val dbCategories = db.getCategories().executeAsBlocking()
|
||||
downloadCategory.apply {
|
||||
entries = dbCategories.map { it.name }.toTypedArray()
|
||||
entryValues = dbCategories.map { it.id.toString() }.toTypedArray()
|
||||
}
|
||||
|
||||
subscriptions += preferences.downloadNewCategories().asObservable()
|
||||
.subscribe {
|
||||
val selectedCategories = it
|
||||
.mapNotNull { id -> dbCategories.find { it.id == id.toInt() } }
|
||||
.sortedBy { it.order }
|
||||
|
||||
val summary = if (selectedCategories.isEmpty())
|
||||
getString(R.string.all)
|
||||
else
|
||||
selectedCategories.joinToString { it.name }
|
||||
|
||||
downloadCategory.summary = summary
|
||||
}
|
||||
}
|
||||
|
||||
fun getExternalFilesDirs(): List<File> {
|
||||
|
@ -1,6 +1,9 @@
|
||||
package eu.kanade.tachiyomi.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v4.os.EnvironmentCompat
|
||||
@ -73,8 +76,9 @@ object DiskUtil {
|
||||
/**
|
||||
* Returns the root folders of all the available external storages.
|
||||
*/
|
||||
fun getExternalStorages(context: Context): List<File> {
|
||||
return ContextCompat.getExternalFilesDirs(context, null)
|
||||
fun getExternalStorages(context: Context): Collection<File> {
|
||||
val directories = mutableSetOf<File>()
|
||||
directories += ContextCompat.getExternalFilesDirs(context, null)
|
||||
.filterNotNull()
|
||||
.mapNotNull {
|
||||
val file = File(it.absolutePath.substringBefore("/Android/"))
|
||||
@ -85,6 +89,29 @@ object DiskUtil {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
val extStorages = System.getenv("SECONDARY_STORAGE")
|
||||
if (extStorages != null) {
|
||||
directories += extStorages.split(":").map(::File)
|
||||
}
|
||||
}
|
||||
|
||||
return directories
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given file so that it can be shown in gallery apps, for example.
|
||||
*/
|
||||
fun scanMedia(context: Context, file: File) {
|
||||
val action = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
Intent.ACTION_MEDIA_MOUNTED
|
||||
} else {
|
||||
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
|
||||
}
|
||||
val mediaScanIntent = Intent(action)
|
||||
mediaScanIntent.data = Uri.fromFile(file)
|
||||
context.sendBroadcast(mediaScanIntent)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,8 +13,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorAccent"
|
||||
android:elevation="5dp"
|
||||
android:visibility="invisible"
|
||||
/>
|
||||
android:visibility="invisible"/>
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipe_refresh"
|
||||
@ -36,6 +35,17 @@
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
<eu.davidea.fastscroller.FastScroller
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/fast_scroller"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_gravity="end"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
style="@style/Theme.Widget.FAB"
|
||||
|
@ -1,298 +1,269 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context="eu.kanade.tachiyomi.ui.catalogue.CatalogueFragment"
|
||||
android:id="@id/swipe_refresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="eu.kanade.tachiyomi.ui.catalogue.CatalogueFragment">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@id/swipe_refresh"
|
||||
<android.support.constraint.ConstraintLayout
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/global_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/guideline"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_percent="0.38"/>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/top_view"
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/guideline2"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.38"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/backdrop"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:alpha="0.2"
|
||||
tools:background="@color/material_grey_700"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/manga_cover"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:contentDescription="@string/description_cover"
|
||||
tools:background="@color/material_grey_700"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline2"/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab_favorite"
|
||||
style="@style/Theme.Widget.FAB"
|
||||
app:srcCompat="@drawable/ic_bookmark_border_white_24dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:layout_marginRight="8dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/guideline"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline"
|
||||
app:layout_constraintRight_toRightOf="parent"/>
|
||||
|
||||
<android.support.v4.widget.NestedScrollView
|
||||
android:id="@+id/info_scrollview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginRight="16dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guideline2"
|
||||
app:layout_constraintRight_toRightOf="parent">
|
||||
|
||||
<android.support.constraint.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="0.4">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/backdrop"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:alpha="0.2"
|
||||
android:contentDescription="@string/description_backdrop"/>
|
||||
<TextView
|
||||
android:id="@+id/manga_author_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/manga_info_author_label"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/manga_author"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_author_label"
|
||||
app:layout_constraintLeft_toRightOf="@+id/manga_author_label"
|
||||
app:layout_constraintRight_toRightOf="parent"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/manga_cover"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="@dimen/activity_vertical_margin"
|
||||
android:layout_weight="0.35"
|
||||
android:contentDescription="@string/description_cover"/>
|
||||
<TextView
|
||||
android:id="@+id/manga_artist_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/manga_info_artist_label"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_author_label"
|
||||
app:layout_constraintLeft_toLeftOf="parent"/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="@dimen/activity_vertical_margin"
|
||||
android:layout_weight="0.65">
|
||||
<TextView
|
||||
android:id="@+id/manga_artist"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_artist_label"
|
||||
app:layout_constraintLeft_toRightOf="@+id/manga_artist_label"
|
||||
app:layout_constraintRight_toRightOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_chapters_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/manga_info_chapters_label"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_artist_label"
|
||||
app:layout_constraintLeft_toLeftOf="parent"/>
|
||||
|
||||
<android.support.v4.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<TextView
|
||||
android:id="@+id/manga_chapters"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_chapters_label"
|
||||
app:layout_constraintLeft_toRightOf="@+id/manga_chapters_label"
|
||||
app:layout_constraintRight_toRightOf="parent"/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<TextView
|
||||
android:id="@+id/manga_status_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/manga_info_status_label"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_chapters_label"
|
||||
app:layout_constraintLeft_toLeftOf="parent"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/manga_author_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/manga_status"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_status_label"
|
||||
app:layout_constraintLeft_toRightOf="@+id/manga_status_label"
|
||||
app:layout_constraintRight_toRightOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_author_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:paddingRight="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/manga_info_author_label"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/manga_source_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/manga_info_source_label"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_status_label"
|
||||
app:layout_constraintLeft_toLeftOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_author"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/manga_source"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_source_label"
|
||||
app:layout_constraintLeft_toRightOf="@+id/manga_source_label"
|
||||
app:layout_constraintRight_toRightOf="parent"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/manga_artist_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/manga_author_view"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/manga_genres_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/manga_info_genres_label"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_source_label"
|
||||
app:layout_constraintLeft_toLeftOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_artist_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:paddingRight="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/manga_info_artist_label"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/manga_genres"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_genres_label"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_artist"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/manga_chapters_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/manga_artist_view"
|
||||
android:orientation="horizontal">
|
||||
</android.support.v4.widget.NestedScrollView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_chapters_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:paddingRight="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/manga_info_chapters_label"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
<android.support.v4.widget.NestedScrollView
|
||||
android:id="@+id/description_scrollview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_chapters"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/manga_status_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/manga_chapters_view"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_status_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:paddingRight="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/manga_info_status_label"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_status"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/manga_source_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/manga_status_view"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_source_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:paddingRight="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/manga_info_source_label"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_source"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/manga_genres_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/manga_source_view"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_genres_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:paddingRight="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/manga_info_genres_label"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_genres"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="false"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</android.support.v4.widget.NestedScrollView>
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<android.support.v4.widget.NestedScrollView
|
||||
android:id="@+id/bottom_view"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="@dimen/activity_vertical_margin"
|
||||
android:layout_weight="0.6">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
<TextView
|
||||
android:id="@+id/manga_summary_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:maxLines="1"
|
||||
android:text="@string/description"
|
||||
android:textIsSelectable="false"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_summary_label"
|
||||
style="@style/TextAppearance.Medium.Body2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:paddingRight="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/description"
|
||||
android:textIsSelectable="false"/>
|
||||
<TextView
|
||||
android:id="@+id/manga_summary"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textIsSelectable="false"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_summary"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="false"
|
||||
android:textIsSelectable="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.v4.widget.NestedScrollView>
|
||||
</android.support.v4.widget.NestedScrollView>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab_favorite"
|
||||
style="@style/Theme.Widget.FAB"
|
||||
android:layout_gravity=""
|
||||
app:layout_anchor="@id/top_view"
|
||||
app:layout_anchorGravity="bottom|right|end"
|
||||
app:layout_behavior=""
|
||||
app:srcCompat="@drawable/ic_bookmark_border_white_24dp"/>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
@ -1,6 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<changelog bulletedList="true">
|
||||
|
||||
<changelogversion versionName="v0.5.1" changeDate="">
|
||||
<changelogtext>Added an option to auto download from selected categories.</changelogtext>
|
||||
|
||||
<changelogtext>Handle a few more directories for local manga.</changelogtext>
|
||||
|
||||
<changelogtext>Update Kissmanga parser.</changelogtext>
|
||||
|
||||
<changelogtext>Fixed downloader errors with some manga titles.</changelogtext>
|
||||
|
||||
<changelogtext>Fixed gallery not showing saved images.</changelogtext>
|
||||
</changelogversion>
|
||||
|
||||
<changelogversion versionName="v0.5.0" changeDate="">
|
||||
<changelogtext>Support for local manga. Head to the [a href="https://github.com/inorichi/tachiyomi/wiki/Local-manga"]wiki page[/a] for instructions.</changelogtext>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<resources>
|
||||
<string name="name">Name</string>
|
||||
<string name="name">Tên</string>
|
||||
|
||||
<!-- Activities and fragments labels (toolbar title) -->
|
||||
<string name="label_settings">Cài đặt</string>
|
||||
@ -24,14 +24,14 @@
|
||||
<string name="action_sort_alpha">Theo bảng chữ cái</string>
|
||||
<string name="action_sort_last_read">Đọc gần nhất</string>
|
||||
<string name="action_sort_last_updated">Cập nhật mới nhất</string>
|
||||
<string name="action_search">Tìm iếm</string>
|
||||
<string name="action_search">Tìm kiếm</string>
|
||||
<string name="action_select_all">Chọn tất cả</string>
|
||||
<string name="action_mark_as_read">Đánh dấu là đã đọc</string>
|
||||
<string name="action_mark_as_unread">Đánh dấu là chưa đọc</string>
|
||||
<string name="action_mark_previous_as_read">Đánh dấu các chương trước là đã đọc</string>
|
||||
<string name="action_download">Tải xuống</string>
|
||||
<string name="action_bookmark">Đánh dấu</string>
|
||||
<string name="action_remove_bookmark">Gỡ đánh dấu</string>
|
||||
<string name="action_remove_bookmark">Bỏ đánh dấu</string>
|
||||
<string name="action_delete">Xóa</string>
|
||||
<string name="action_update">Cập nhật</string>
|
||||
<string name="action_update_library">Cập nhật thư viện</string>
|
||||
@ -90,7 +90,7 @@
|
||||
<string name="portrait">Dọc</string>
|
||||
<string name="landscape">Ngang</string>
|
||||
<string name="default_columns">Mặc định</string>
|
||||
<string name="pref_library_update_interval">Thời gian cập nhật thư viện</string>
|
||||
<string name="pref_library_update_interval">Lịch cập nhật thư viện</string>
|
||||
<string name="update_never">Thủ công</string>
|
||||
<string name="update_1hour">Mỗi giờ</string>
|
||||
<string name="update_2hour">Mỗi 2 giờ</string>
|
||||
@ -184,7 +184,7 @@
|
||||
<string name="cache_delete_error">Lỗi đã xày ra khi xóa bộ nhớ đệm</string>
|
||||
<string name="pref_clear_cookies">Dọn dẹp cookies</string>
|
||||
<string name="cookies_cleared">Cookies đã được dọn dẹp</string>
|
||||
<string name="choices_reset">Dialog choices reset</string>
|
||||
<string name="choices_reset">Thiết lập lại các hộp thoại</string>
|
||||
<string name="pref_clear_database">Dọn dẹp cơ sở dữ liệu</string>
|
||||
<string name="pref_clear_database_summary">Xóa các truyện và các chương không nằm trong thư viện</string>
|
||||
<string name="clear_database_confirmation">Bạn có chắc không? Các chương đã đọc và tiến độ đọc các truyện không nằm trong thư viện sẽ bị mất</string>
|
||||
@ -245,7 +245,7 @@
|
||||
<string name="rounded_icon">Biểu tượng hình chữ nhật</string>
|
||||
<string name="square_icon">Biểu tượng vuông</string>
|
||||
<string name="star_icon">Biểu tượng ngôi sao</string>
|
||||
<string name="shortcut_title">Tiêu đề lối tắt</string>
|
||||
<string name="shortcut_title">Tiêu đề của lối tắt</string>
|
||||
<string name="icon_shape">Kiểu biểu tượng</string>
|
||||
<string name="icon_creation_fail">Tạo lối tắt thất bại!</string>
|
||||
|
||||
|
@ -68,6 +68,7 @@
|
||||
<string name="pref_last_catalogue_source_key" translatable="false">last_catalogue_source</string>
|
||||
|
||||
<string name="pref_download_new_key" translatable="false">download_new</string>
|
||||
<string name="pref_download_new_categories_key" translatable="false">download_new_categories</string>
|
||||
|
||||
<!-- String Fonts -->
|
||||
<string name="font_roboto_medium" translatable="false">sans-serif</string>
|
||||
|
@ -176,6 +176,7 @@
|
||||
<string name="fourth_to_last">Fourth to last chapter</string>
|
||||
<string name="fifth_to_last">Fifth to last chapter</string>
|
||||
<string name="pref_download_new">Download new chapters</string>
|
||||
<string name="pref_download_new_categories">Categories to include in download</string>
|
||||
|
||||
<!-- Sync section -->
|
||||
<string name="services">Services</string>
|
||||
|
@ -53,6 +53,10 @@
|
||||
android:key="@string/pref_download_new_key"
|
||||
android:title="@string/pref_download_new"/>
|
||||
|
||||
<MultiSelectListPreference
|
||||
android:key="@string/pref_download_new_categories_key"
|
||||
android:title="@string/pref_download_new_categories" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
</PreferenceScreen>
|
@ -6,7 +6,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.2.3'
|
||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.13.0'
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
@ -17,6 +17,5 @@ allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url "https://jitpack.io" }
|
||||
maven { url "https://dl.bintray.com/inorichi/maven" }
|
||||
}
|
||||
}
|
||||
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
#Sat Aug 27 15:18:00 CEST 2016
|
||||
#Fri Mar 03 16:14:18 CET 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
|
||||
|
Reference in New Issue
Block a user