Add favorites downloader.
This commit is contained in:
parent
492adb7035
commit
d981c75600
@ -22,7 +22,10 @@ import java.util.*
|
|||||||
import exh.ui.login.LoginActivity
|
import exh.ui.login.LoginActivity
|
||||||
import exh.util.UriFilter
|
import exh.util.UriFilter
|
||||||
import exh.util.UriGroup
|
import exh.util.UriGroup
|
||||||
|
import okhttp3.CacheControl
|
||||||
|
import okhttp3.Headers
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
|
||||||
class EHentai(override val id: Long,
|
class EHentai(override val id: Long,
|
||||||
val exh: Boolean,
|
val exh: Boolean,
|
||||||
@ -38,7 +41,7 @@ class EHentai(override val id: Long,
|
|||||||
get() = if(exh)
|
get() = if(exh)
|
||||||
"$schema://exhentai.org"
|
"$schema://exhentai.org"
|
||||||
else
|
else
|
||||||
"http://e-hentai.org"
|
"$schema://e-hentai.org"
|
||||||
|
|
||||||
override val lang = "all"
|
override val lang = "all"
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
@ -52,11 +55,8 @@ class EHentai(override val id: Long,
|
|||||||
*/
|
*/
|
||||||
data class ParsedManga(val fav: String?, val manga: Manga)
|
data class ParsedManga(val fav: String?, val manga: Manga)
|
||||||
|
|
||||||
/**
|
fun extendedGenericMangaParse(doc: Document)
|
||||||
* Parse a list of galleries
|
= with(doc) {
|
||||||
*/
|
|
||||||
fun genericMangaParse(response: Response)
|
|
||||||
= with(response.asJsoup()) {
|
|
||||||
//Parse mangas
|
//Parse mangas
|
||||||
val parsedMangas = select(".gtr0,.gtr1").map {
|
val parsedMangas = select(".gtr0,.gtr1").map {
|
||||||
ParsedManga(
|
ParsedManga(
|
||||||
@ -84,7 +84,15 @@ class EHentai(override val id: Long,
|
|||||||
val hasNextPage = select("a[onclick=return false]").last()?.let {
|
val hasNextPage = select("a[onclick=return false]").last()?.let {
|
||||||
it.text() == ">"
|
it.text() == ">"
|
||||||
} ?: false
|
} ?: false
|
||||||
MangasPage(parsedMangas.map { it.manga }, hasNextPage)
|
Pair(parsedMangas, hasNextPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a list of galleries
|
||||||
|
*/
|
||||||
|
fun genericMangaParse(response: Response)
|
||||||
|
= extendedGenericMangaParse(response.asJsoup()).let {
|
||||||
|
MangasPage(it.first.map { it.manga }, it.second)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>>
|
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>>
|
||||||
@ -143,16 +151,29 @@ class EHentai(override val id: Long,
|
|||||||
return exGet(uri.toString(), page)
|
return exGet(uri.toString(), page)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int) = exGet(baseUrl, page)
|
override fun latestUpdatesRequest(page: Int) = exGet(baseUrl, page)!!
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response) = genericMangaParse(response)
|
override fun popularMangaParse(response: Response) = genericMangaParse(response)
|
||||||
override fun searchMangaParse(response: Response) = genericMangaParse(response)
|
override fun searchMangaParse(response: Response) = genericMangaParse(response)
|
||||||
override fun latestUpdatesParse(response: Response) = genericMangaParse(response)
|
override fun latestUpdatesParse(response: Response) = genericMangaParse(response)
|
||||||
|
|
||||||
fun exGet(url: String, page: Int? = null)
|
fun exGet(url: String, page: Int? = null, additionalHeaders: Headers? = null, cache: Boolean = true)
|
||||||
= GET(page?.let {
|
= GET(page?.let {
|
||||||
addParam(url, "page", Integer.toString(page - 1))
|
addParam(url, "page", Integer.toString(page - 1))
|
||||||
} ?: url, headers)
|
} ?: url, additionalHeaders?.let {
|
||||||
|
val headers = headers.newBuilder()
|
||||||
|
it.toMultimap().forEach { t, u ->
|
||||||
|
u.forEach {
|
||||||
|
headers.add(t, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
headers.build()
|
||||||
|
} ?: headers).let {
|
||||||
|
if(!cache)
|
||||||
|
it.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build()
|
||||||
|
else
|
||||||
|
it
|
||||||
|
}!!
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse gallery page to metadata model
|
* Parse gallery page to metadata model
|
||||||
@ -266,6 +287,37 @@ class EHentai(override val id: Long,
|
|||||||
throw UnsupportedOperationException("Unused method was called somehow!")
|
throw UnsupportedOperationException("Unused method was called somehow!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Too lazy to write return type
|
||||||
|
fun fetchFavorites() = {
|
||||||
|
//Used to get "s" cookie
|
||||||
|
val favoriteUrl = "$baseUrl/favorites.php"
|
||||||
|
val result = mutableListOf<ParsedManga>()
|
||||||
|
var page = 1
|
||||||
|
|
||||||
|
var favNames: List<String>? = null
|
||||||
|
|
||||||
|
do {
|
||||||
|
val response2 = client.newCall(exGet(favoriteUrl,
|
||||||
|
page = page,
|
||||||
|
cache = false)).execute()
|
||||||
|
val doc = response2.asJsoup()
|
||||||
|
|
||||||
|
//Parse favorites
|
||||||
|
val parsed = extendedGenericMangaParse(doc)
|
||||||
|
result += parsed.first
|
||||||
|
|
||||||
|
//Parse fav names
|
||||||
|
if (favNames == null)
|
||||||
|
favNames = doc.getElementsByClass("nosel").first().children().filter {
|
||||||
|
it.children().size >= 3
|
||||||
|
}.map { it.child(2).text() }.filterNotNull()
|
||||||
|
|
||||||
|
//Next page
|
||||||
|
page++
|
||||||
|
} while (parsed.second)
|
||||||
|
Pair(result as List<ParsedManga>, favNames!!)
|
||||||
|
}()
|
||||||
|
|
||||||
val cookiesHeader by lazy {
|
val cookiesHeader by lazy {
|
||||||
val cookies: MutableMap<String, String> = mutableMapOf()
|
val cookies: MutableMap<String, String> = mutableMapOf()
|
||||||
if(prefs.enableExhentai().getOrDefault()) {
|
if(prefs.enableExhentai().getOrDefault()) {
|
||||||
@ -403,5 +455,20 @@ class EHentai(override val id: Long,
|
|||||||
companion object {
|
companion object {
|
||||||
val QUERY_PREFIX = "?f_apply=Apply+Filter"
|
val QUERY_PREFIX = "?f_apply=Apply+Filter"
|
||||||
val TR_SUFFIX = "TR"
|
val TR_SUFFIX = "TR"
|
||||||
|
|
||||||
|
fun getCookies(cookies: String): Map<String, String>? {
|
||||||
|
val foundCookies = HashMap<String, String>()
|
||||||
|
for (cookie in cookies.split(";".toRegex()).dropLastWhile(String::isEmpty).toTypedArray()) {
|
||||||
|
val splitCookie = cookie.split("=".toRegex()).dropLastWhile(String::isEmpty).toTypedArray()
|
||||||
|
if (splitCookie.size < 2) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val trimmedKey = splitCookie[0].trim { it <= ' ' }
|
||||||
|
if (!foundCookies.containsKey(trimmedKey)) {
|
||||||
|
foundCookies.put(trimmedKey, splitCookie[1].trim { it <= ' ' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundCookies
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.ui.main.MainActivity
|
|||||||
import eu.kanade.tachiyomi.util.inflate
|
import eu.kanade.tachiyomi.util.inflate
|
||||||
import eu.kanade.tachiyomi.util.toast
|
import eu.kanade.tachiyomi.util.toast
|
||||||
import eu.kanade.tachiyomi.widget.DialogCheckboxView
|
import eu.kanade.tachiyomi.widget.DialogCheckboxView
|
||||||
|
import exh.FavoritesSyncHelper
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import kotlinx.android.synthetic.main.fragment_library.*
|
import kotlinx.android.synthetic.main.fragment_library.*
|
||||||
import nucleus.factory.RequiresPresenter
|
import nucleus.factory.RequiresPresenter
|
||||||
@ -267,6 +268,11 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
|||||||
val intent = CategoryActivity.newIntent(activity)
|
val intent = CategoryActivity.newIntent(activity)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
R.id.action_sync -> {
|
||||||
|
FavoritesSyncHelper(this.activity).guiSyncFavorites({
|
||||||
|
//Do we even need stuff in here?
|
||||||
|
})
|
||||||
|
}
|
||||||
else -> return super.onOptionsItemSelected(item)
|
else -> return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
135
app/src/main/java/exh/FavoritesSyncHelper.kt
Normal file
135
app/src/main/java/exh/FavoritesSyncHelper.kt
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package exh
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.support.v7.app.AlertDialog
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
|
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
||||||
|
import timber.log.Timber
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
class FavoritesSyncHelper(val activity: Activity) {
|
||||||
|
|
||||||
|
val db: DatabaseHelper by injectLazy()
|
||||||
|
|
||||||
|
val sourceManager: SourceManager by injectLazy()
|
||||||
|
|
||||||
|
val prefs: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
fun guiSyncFavorites(onComplete: () -> Unit) {
|
||||||
|
//ExHentai must be enabled/user must be logged in
|
||||||
|
if (!prefs.enableExhentai().getOrDefault()) {
|
||||||
|
AlertDialog.Builder(activity).setTitle("Error")
|
||||||
|
.setMessage("You are not logged in! Please log in and try again!")
|
||||||
|
.setPositiveButton("Ok") { dialog, _ -> dialog.dismiss() }.show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val dialog = MaterialDialog.Builder(activity)
|
||||||
|
.progress(true, 0)
|
||||||
|
.title("Downloading favorites")
|
||||||
|
.content("Please wait...")
|
||||||
|
.cancelable(false)
|
||||||
|
.show()
|
||||||
|
thread {
|
||||||
|
var error = false
|
||||||
|
try {
|
||||||
|
syncFavorites()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
error = true
|
||||||
|
Timber.e(e, "Could not sync favorites!")
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.dismiss()
|
||||||
|
|
||||||
|
activity.runOnUiThread {
|
||||||
|
if (error)
|
||||||
|
MaterialDialog.Builder(activity)
|
||||||
|
.title("Error")
|
||||||
|
.content("There was an error downloading your favorites, please try again later!")
|
||||||
|
.positiveText("Ok")
|
||||||
|
.show()
|
||||||
|
onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun syncFavorites() {
|
||||||
|
val onlineSources = sourceManager.getOnlineSources()
|
||||||
|
var ehSource: EHentai? = null
|
||||||
|
var exSource: EHentai? = null
|
||||||
|
onlineSources.forEach {
|
||||||
|
if(it.id == EH_SOURCE_ID)
|
||||||
|
ehSource = it as EHentai
|
||||||
|
else if(it.id == EXH_SOURCE_ID)
|
||||||
|
exSource = it as EHentai
|
||||||
|
}
|
||||||
|
|
||||||
|
(exSource ?: ehSource)?.let { source ->
|
||||||
|
val favResponse = source.fetchFavorites()
|
||||||
|
val ourCategories = ArrayList<Category>(db.getCategories().executeAsBlocking())
|
||||||
|
val ourMangas = ArrayList<Manga>(db.getMangas().executeAsBlocking())
|
||||||
|
//Add required categories (categories do not sync upwards)
|
||||||
|
favResponse.second.filter { theirCategory ->
|
||||||
|
ourCategories.find {
|
||||||
|
it.name.endsWith(theirCategory)
|
||||||
|
} == null
|
||||||
|
}.map {
|
||||||
|
Category.create(it)
|
||||||
|
}.let {
|
||||||
|
db.inTransaction {
|
||||||
|
//Insert new categories
|
||||||
|
db.insertCategories(it).executeAsBlocking().results().entries.filter {
|
||||||
|
it.value.wasInserted()
|
||||||
|
}.forEach { it.key.id = it.value.insertedId()!!.toInt() }
|
||||||
|
|
||||||
|
val categoryMap = (it + ourCategories).associateBy { it.name }
|
||||||
|
|
||||||
|
//Insert new mangas
|
||||||
|
val mangaToInsert = java.util.ArrayList<Manga>()
|
||||||
|
favResponse.first.map {
|
||||||
|
val category = categoryMap[it.fav]!!
|
||||||
|
var manga = it.manga
|
||||||
|
val alreadyHaveManga = ourMangas.find {
|
||||||
|
it.url == manga.url
|
||||||
|
}?.apply {
|
||||||
|
manga = this
|
||||||
|
} != null
|
||||||
|
if (!alreadyHaveManga) {
|
||||||
|
ourMangas.add(manga)
|
||||||
|
mangaToInsert.add(manga)
|
||||||
|
}
|
||||||
|
manga.favorite = true
|
||||||
|
Pair(manga, category)
|
||||||
|
}.apply {
|
||||||
|
//Insert mangas
|
||||||
|
db.insertMangas(mangaToInsert).executeAsBlocking().results().entries.filter {
|
||||||
|
it.value.wasInserted()
|
||||||
|
}.forEach { manga ->
|
||||||
|
manga.key.id = manga.value.insertedId()
|
||||||
|
try {
|
||||||
|
source.fetchChapterList(manga.key).map {
|
||||||
|
syncChaptersWithSource(db, it, manga.key, source)
|
||||||
|
}.toBlocking().first()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.w(e, "Failed to update chapters for gallery: ${manga.key.title}!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set categories
|
||||||
|
val categories = map { MangaCategory.create(it.first, it.second) }
|
||||||
|
val mangas = map { it.first }
|
||||||
|
db.setMangaCategories(categories, mangas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,11 +20,12 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper;
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Category;
|
import eu.kanade.tachiyomi.data.database.models.Category;
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga;
|
import eu.kanade.tachiyomi.data.database.models.Manga;
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory;
|
import eu.kanade.tachiyomi.data.database.models.MangaCategory;
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.EHentai;
|
||||||
|
import kotlin.Pair;
|
||||||
//import eu.kanade.tachiyomi.data.source.online.english.EHentai;
|
//import eu.kanade.tachiyomi.data.source.online.english.EHentai;
|
||||||
|
|
||||||
public class FavoritesSyncManager {
|
public class FavoritesSyncManager {
|
||||||
/*
|
/*Context context;
|
||||||
Context context;
|
|
||||||
DatabaseHelper db;
|
DatabaseHelper db;
|
||||||
|
|
||||||
public FavoritesSyncManager(Context context, DatabaseHelper db) {
|
public FavoritesSyncManager(Context context, DatabaseHelper db) {
|
||||||
@ -72,10 +73,10 @@ public class FavoritesSyncManager {
|
|||||||
mainLooper.post(onComplete);
|
mainLooper.post(onComplete);
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}*/
|
||||||
|
/*
|
||||||
public void syncFavorites() throws IOException {
|
public void syncFavorites() throws IOException {
|
||||||
EHentai.FavoritesResponse favResponse = EHentai.fetchFavorites(context);
|
Pair favResponse = EHentai.fetchFavorites(context);
|
||||||
Map<String, List<Manga>> favorites = favResponse.favs;
|
Map<String, List<Manga>> favorites = favResponse.favs;
|
||||||
List<Category> ourCategories = new ArrayList<>(db.getCategories().executeAsBlocking());
|
List<Category> ourCategories = new ArrayList<>(db.getCategories().executeAsBlocking());
|
||||||
List<Manga> ourMangas = new ArrayList<>(db.getMangas().executeAsBlocking());
|
List<Manga> ourMangas = new ArrayList<>(db.getMangas().executeAsBlocking());
|
||||||
@ -136,7 +137,7 @@ public class FavoritesSyncManager {
|
|||||||
for(Map.Entry<Manga, Category> entry : mangaToSetCategories.entrySet()) {
|
for(Map.Entry<Manga, Category> entry : mangaToSetCategories.entrySet()) {
|
||||||
db.setMangaCategories(Collections.singletonList(MangaCategory.Companion.create(entry.getKey(), entry.getValue())),
|
db.setMangaCategories(Collections.singletonList(MangaCategory.Companion.create(entry.getKey(), entry.getValue())),
|
||||||
Collections.singletonList(entry.getKey()));
|
Collections.singletonList(entry.getKey()));
|
||||||
}
|
}*/
|
||||||
//Determines what
|
//Determines what
|
||||||
/*Map<Integer, List<Manga>> toUpload = new HashMap<>();
|
/*Map<Integer, List<Manga>> toUpload = new HashMap<>();
|
||||||
for (Manga manga : ourMangas) {
|
for (Manga manga : ourMangas) {
|
||||||
|
@ -7,11 +7,18 @@ import android.view.MenuItem
|
|||||||
import android.webkit.CookieManager
|
import android.webkit.CookieManager
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.webkit.WebViewClient
|
import android.webkit.WebViewClient
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
||||||
|
import exh.EXH_SOURCE_ID
|
||||||
import kotlinx.android.synthetic.main.eh_activity_login.*
|
import kotlinx.android.synthetic.main.eh_activity_login.*
|
||||||
import kotlinx.android.synthetic.main.toolbar.*
|
import kotlinx.android.synthetic.main.toolbar.*
|
||||||
|
import rx.Observable
|
||||||
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
import rx.schedulers.Schedulers
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.net.HttpCookie
|
import java.net.HttpCookie
|
||||||
@ -24,6 +31,8 @@ class LoginActivity : BaseActivity() {
|
|||||||
|
|
||||||
val preferenceManager: PreferencesHelper by injectLazy()
|
val preferenceManager: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
val sourceManager: SourceManager by injectLazy()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
setAppTheme()
|
setAppTheme()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -73,13 +82,40 @@ class LoginActivity : BaseActivity() {
|
|||||||
//At ExHentai, check that everything worked out...
|
//At ExHentai, check that everything worked out...
|
||||||
if(applyExHentaiCookies(url)) {
|
if(applyExHentaiCookies(url)) {
|
||||||
preferenceManager.enableExhentai().set(true)
|
preferenceManager.enableExhentai().set(true)
|
||||||
onBackPressed()
|
finishLogin()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun finishLogin() {
|
||||||
|
val progressDialog = MaterialDialog.Builder(this)
|
||||||
|
.title("Finalizing login")
|
||||||
|
.progress(true, 0)
|
||||||
|
.content("Please wait...")
|
||||||
|
.cancelable(false)
|
||||||
|
.show()
|
||||||
|
|
||||||
|
val eh = sourceManager
|
||||||
|
.getOnlineSources()
|
||||||
|
.find { it.id == EXH_SOURCE_ID } as EHentai
|
||||||
|
Observable.fromCallable {
|
||||||
|
//I honestly have no idea why we need to call this twice, but it works, so whatever
|
||||||
|
try {
|
||||||
|
eh.fetchFavorites()
|
||||||
|
} catch(ignored: Exception) {}
|
||||||
|
try {
|
||||||
|
eh.fetchFavorites()
|
||||||
|
} catch(ignored: Exception) {}
|
||||||
|
}.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe {
|
||||||
|
progressDialog.dismiss()
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if we are logged in
|
* Check if we are logged in
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM17,13l-5,5 -5,-5h3V9h4v4h3z"/>
|
||||||
|
</vector>
|
@ -22,9 +22,14 @@
|
|||||||
android:title="@string/action_update_library"
|
android:title="@string/action_update_library"
|
||||||
app:showAsAction="ifRoom"/>
|
app:showAsAction="ifRoom"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sync"
|
||||||
|
android:icon="@drawable/ic_cloud_download_white_24dp"
|
||||||
|
android:title="Download favorites"
|
||||||
|
app:showAsAction="ifRoom"/>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_edit_categories"
|
android:id="@+id/action_edit_categories"
|
||||||
android:title="@string/action_edit_categories"
|
android:title="@string/action_edit_categories"
|
||||||
app:showAsAction="never"/>
|
app:showAsAction="never"/>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -31,11 +31,10 @@
|
|||||||
android:defaultValue="false" />
|
android:defaultValue="false" />
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:dependency="enable_exhentai"
|
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="secure_exh"
|
android:key="secure_exh"
|
||||||
android:title="Secure ExHentai"
|
android:title="Secure ExHentai/E-Hentai"
|
||||||
android:summary="Use the HTTPS version of ExHentai. Uncheck if ExHentai is not working" />
|
android:summary="Use the HTTPS version of ExHentai/E-Hentai." />
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="auto"
|
android:defaultValue="auto"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user