mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-27 11:37:51 +02:00
Merge branch 'master' of https://github.com/inorichi/tachiyomi
# Conflicts: # README.md # app/build.gradle # app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt # app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt # app/src/main/res/layout/manga_info_controller.xml # app/src/main/res/raw/changelog_release.xml
This commit is contained in:
@ -14,7 +14,7 @@ data class ALManga(
|
||||
val id: Int,
|
||||
val title_romaji: String,
|
||||
val image_url_lge: String,
|
||||
val description: String,
|
||||
val description: String?,
|
||||
val type: String,
|
||||
val publishing_status: String,
|
||||
val start_date_fuzzy: String,
|
||||
@ -25,7 +25,7 @@ data class ALManga(
|
||||
title = title_romaji
|
||||
total_chapters = this@ALManga.total_chapters
|
||||
cover_url = image_url_lge
|
||||
summary = description
|
||||
summary = description ?: ""
|
||||
tracking_url = AnilistApi.mangaUrl(remote_id)
|
||||
publishing_status = this@ALManga.publishing_status
|
||||
publishing_type = type
|
||||
@ -39,7 +39,6 @@ data class ALManga(
|
||||
start_date_fuzzy.orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,9 +132,6 @@ class ExtensionManager(
|
||||
* Returns the relay of the available extensions as an observable.
|
||||
*/
|
||||
fun getAvailableExtensionsObservable(): Observable<List<Extension.Available>> {
|
||||
if (!availableExtensionsRelay.hasValue()) {
|
||||
findAvailableExtensions()
|
||||
}
|
||||
return availableExtensionsRelay.asObservable()
|
||||
}
|
||||
|
||||
@ -204,6 +201,16 @@ class ExtensionManager(
|
||||
return installExtension(availableExt)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the result of the installation of an extension.
|
||||
*
|
||||
* @param downloadId The id of the download.
|
||||
* @param result Whether the extension was installed or not.
|
||||
*/
|
||||
fun setInstallationResult(downloadId: Long, result: Boolean) {
|
||||
installer.setInstallationResult(downloadId, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls the extension that matches the given package name.
|
||||
*
|
||||
@ -298,17 +305,14 @@ class ExtensionManager(
|
||||
|
||||
override fun onExtensionInstalled(extension: Extension.Installed) {
|
||||
registerNewExtension(extension.withUpdateCheck())
|
||||
installer.onApkInstalled(extension.pkgName)
|
||||
}
|
||||
|
||||
override fun onExtensionUpdated(extension: Extension.Installed) {
|
||||
registerUpdatedExtension(extension.withUpdateCheck())
|
||||
installer.onApkInstalled(extension.pkgName)
|
||||
}
|
||||
|
||||
override fun onExtensionUntrusted(extension: Extension.Untrusted) {
|
||||
untrustedExtensions += extension
|
||||
installer.onApkInstalled(extension.pkgName)
|
||||
}
|
||||
|
||||
override fun onPackageUninstalled(pkgName: String) {
|
||||
|
@ -0,0 +1,52 @@
|
||||
package eu.kanade.tachiyomi.extension.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
/**
|
||||
* Activity used to install extensions, because we can only receive the result of the installation
|
||||
* with [startActivityForResult], which we need to update the UI.
|
||||
*/
|
||||
class ExtensionInstallActivity : Activity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
|
||||
.setDataAndType(intent.data, intent.type)
|
||||
.putExtra(Intent.EXTRA_RETURN_RESULT, true)
|
||||
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
||||
try {
|
||||
startActivityForResult(installIntent, INSTALL_REQUEST_CODE)
|
||||
} catch (error: Exception) {
|
||||
// Either install package can't be found (probably bots) or there's a security exception
|
||||
// with the download manager. Nothing we can workaround.
|
||||
toast(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == INSTALL_REQUEST_CODE) {
|
||||
checkInstallationResult(resultCode)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun checkInstallationResult(resultCode: Int) {
|
||||
val downloadId = intent.extras.getLong(ExtensionInstaller.EXTRA_DOWNLOAD_ID)
|
||||
val success = resultCode == RESULT_OK
|
||||
|
||||
val extensionManager = Injekt.get<ExtensionManager>()
|
||||
extensionManager.setInstallationResult(downloadId, success)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val INSTALL_REQUEST_CODE = 500
|
||||
}
|
||||
}
|
@ -77,8 +77,6 @@ internal class ExtensionInstaller(private val context: Context) {
|
||||
.mergeWith(pollStatus(id))
|
||||
// Force an error if the download takes more than 3 minutes
|
||||
.mergeWith(Observable.timer(3, TimeUnit.MINUTES).map { InstallStep.Error })
|
||||
// Force an error if the install process takes more than 10 seconds
|
||||
.flatMap { Observable.just(it).mergeWith(timeoutWhenInstalling(it)) }
|
||||
// Stop when the application is installed or errors
|
||||
.takeUntil { it.isCompleted() }
|
||||
// Always notify on main thread
|
||||
@ -118,27 +116,15 @@ internal class ExtensionInstaller(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an observable that timeouts the installation after a specified time when the apk has
|
||||
* been downloaded.
|
||||
*
|
||||
* @param currentStep The current step of the installation process.
|
||||
*/
|
||||
private fun timeoutWhenInstalling(currentStep: InstallStep): Observable<InstallStep> {
|
||||
return Observable.just(currentStep)
|
||||
.filter { it == InstallStep.Installing }
|
||||
.delay(10, TimeUnit.SECONDS)
|
||||
.map { InstallStep.Error }
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an intent to install the extension at the given uri.
|
||||
*
|
||||
* @param uri The uri of the extension to install.
|
||||
*/
|
||||
fun installApk(uri: Uri) {
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
fun installApk(downloadId: Long, uri: Uri) {
|
||||
val intent = Intent(context, ExtensionInstallActivity::class.java)
|
||||
.setDataAndType(uri, APK_MIME)
|
||||
.putExtra(EXTRA_DOWNLOAD_ID, downloadId)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
||||
context.startActivity(intent)
|
||||
@ -158,13 +144,14 @@ internal class ExtensionInstaller(private val context: Context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an extension is installed, allowing to update its installation step.
|
||||
* Sets the result of the installation of an extension.
|
||||
*
|
||||
* @param pkgName The package name of the installed application.
|
||||
* @param downloadId The id of the download.
|
||||
* @param result Whether the extension was installed or not.
|
||||
*/
|
||||
fun onApkInstalled(pkgName: String) {
|
||||
val id = activeDownloads[pkgName] ?: return
|
||||
downloadsRelay.call(id to InstallStep.Installed)
|
||||
fun setInstallationResult(downloadId: Long, result: Boolean) {
|
||||
val step = if (result) InstallStep.Installed else InstallStep.Error
|
||||
downloadsRelay.call(downloadId to step)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,17 +230,18 @@ internal class ExtensionInstaller(private val context: Context) {
|
||||
@Suppress("DEPRECATION")
|
||||
val uriCompat = File(cursor.getString(cursor.getColumnIndex(
|
||||
DownloadManager.COLUMN_LOCAL_FILENAME))).getUriCompat(context)
|
||||
installApk(uriCompat)
|
||||
installApk(id, uriCompat)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
installApk(uri)
|
||||
installApk(id, uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
companion object {
|
||||
const val APK_MIME = "application/vnd.android.package-archive"
|
||||
const val EXTRA_DOWNLOAD_ID = "ExtensionInstaller.extra.DOWNLOAD_ID"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -66,7 +66,12 @@ internal object ExtensionLoader {
|
||||
* contains the required feature flag before trying to load it.
|
||||
*/
|
||||
fun loadExtensionFromPkgName(context: Context, pkgName: String): LoadResult {
|
||||
val pkgInfo = context.packageManager.getPackageInfo(pkgName, PACKAGE_FLAGS)
|
||||
val pkgInfo = try {
|
||||
context.packageManager.getPackageInfo(pkgName, PACKAGE_FLAGS)
|
||||
} catch (error: PackageManager.NameNotFoundException) {
|
||||
// Unlikely, but the package may have been uninstalled at this point
|
||||
return LoadResult.Error(error)
|
||||
}
|
||||
if (!isPackageAnExtension(pkgInfo)) {
|
||||
return LoadResult.Error("Tried to load a package that wasn't a extension")
|
||||
}
|
||||
@ -83,9 +88,15 @@ internal object ExtensionLoader {
|
||||
private fun loadExtension(context: Context, pkgName: String, pkgInfo: PackageInfo): LoadResult {
|
||||
val pkgManager = context.packageManager
|
||||
|
||||
val appInfo = pkgManager.getApplicationInfo(pkgName, PackageManager.GET_META_DATA)
|
||||
val appInfo = try {
|
||||
pkgManager.getApplicationInfo(pkgName, PackageManager.GET_META_DATA)
|
||||
} catch (error: PackageManager.NameNotFoundException) {
|
||||
// Unlikely, but the package may have been uninstalled at this point
|
||||
return LoadResult.Error(error)
|
||||
}
|
||||
|
||||
val extName = pkgManager.getApplicationLabel(appInfo).toString().substringAfter("Tachiyomi: ")
|
||||
val extName = pkgManager.getApplicationLabel(appInfo)?.toString()
|
||||
.orEmpty().substringAfter("Tachiyomi: ")
|
||||
val versionName = pkgInfo.versionName
|
||||
val versionCode = pkgInfo.versionCode
|
||||
|
||||
|
@ -226,7 +226,6 @@ class Kissmanga : ParsedHttpSource() {
|
||||
Genre("Mystery"),
|
||||
Genre("One shot"),
|
||||
Genre("Psychological"),
|
||||
Genre("Reincarnation"),
|
||||
Genre("Romance"),
|
||||
Genre("School Life"),
|
||||
Genre("Sci-fi"),
|
||||
@ -240,9 +239,7 @@ class Kissmanga : ParsedHttpSource() {
|
||||
Genre("Smut"),
|
||||
Genre("Sports"),
|
||||
Genre("Supernatural"),
|
||||
Genre("Time Travel"),
|
||||
Genre("Tragedy"),
|
||||
Genre("Transported"),
|
||||
Genre("Webtoon"),
|
||||
Genre("Yaoi"),
|
||||
Genre("Yuri")
|
||||
|
@ -12,6 +12,7 @@ import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.RestoreViewOnCreateController
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.*
|
||||
import timber.log.Timber
|
||||
|
||||
abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateController(bundle),
|
||||
LayoutContainer {
|
||||
@ -21,6 +22,22 @@ abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateContr
|
||||
override fun postCreateView(controller: Controller, view: View) {
|
||||
onViewCreated(view)
|
||||
}
|
||||
|
||||
override fun preCreateView(controller: Controller) {
|
||||
Timber.d("Create view for ${controller.instance()}")
|
||||
}
|
||||
|
||||
override fun preAttach(controller: Controller, view: View) {
|
||||
Timber.d("Attach view for ${controller.instance()}")
|
||||
}
|
||||
|
||||
override fun preDetach(controller: Controller, view: View) {
|
||||
Timber.d("Detach view for ${controller.instance()}")
|
||||
}
|
||||
|
||||
override fun preDestroyView(controller: Controller, view: View) {
|
||||
Timber.d("Destroy view for ${controller.instance()}")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -63,6 +80,10 @@ abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateContr
|
||||
(activity as? AppCompatActivity)?.supportActionBar?.title = getTitle()
|
||||
}
|
||||
|
||||
private fun Controller.instance(): String {
|
||||
return "${javaClass.simpleName}@${Integer.toHexString(hashCode())}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround for disappearing menu items when collapsing an expandable item like a SearchView.
|
||||
* This method should be removed when fixed upstream.
|
||||
@ -81,4 +102,4 @@ abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateContr
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,186 +0,0 @@
|
||||
package eu.kanade.tachiyomi.ui.base.controller;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.bluelinelabs.conductor.Router;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An adapter for ViewPagers that uses Routers as pages
|
||||
*/
|
||||
public abstract class RouterPagerAdapter extends PagerAdapter {
|
||||
|
||||
private static final String KEY_SAVED_PAGES = "RouterPagerAdapter.savedStates";
|
||||
private static final String KEY_MAX_PAGES_TO_STATE_SAVE = "RouterPagerAdapter.maxPagesToStateSave";
|
||||
private static final String KEY_SAVE_PAGE_HISTORY = "RouterPagerAdapter.savedPageHistory";
|
||||
|
||||
private final Controller host;
|
||||
private int maxPagesToStateSave = Integer.MAX_VALUE;
|
||||
private SparseArray<Bundle> savedPages = new SparseArray<>();
|
||||
private SparseArray<Router> visibleRouters = new SparseArray<>();
|
||||
private ArrayList<Integer> savedPageHistory = new ArrayList<>();
|
||||
private Router primaryRouter;
|
||||
|
||||
/**
|
||||
* Creates a new RouterPagerAdapter using the passed host.
|
||||
*/
|
||||
public RouterPagerAdapter(@NonNull Controller host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a router is instantiated. Here the router's root should be set if needed.
|
||||
*
|
||||
* @param router The router used for the page
|
||||
* @param position The page position to be instantiated.
|
||||
*/
|
||||
public abstract void configureRouter(@NonNull Router router, int position);
|
||||
|
||||
/**
|
||||
* Sets the maximum number of pages that will have their states saved. When this number is exceeded,
|
||||
* the page that was state saved least recently will have its state removed from the save data.
|
||||
*/
|
||||
public void setMaxPagesToStateSave(int maxPagesToStateSave) {
|
||||
if (maxPagesToStateSave < 0) {
|
||||
throw new IllegalArgumentException("Only positive integers may be passed for maxPagesToStateSave.");
|
||||
}
|
||||
|
||||
this.maxPagesToStateSave = maxPagesToStateSave;
|
||||
|
||||
ensurePagesSaved();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
final String name = makeRouterName(container.getId(), getItemId(position));
|
||||
|
||||
Router router = host.getChildRouter(container, name);
|
||||
if (!router.hasRootController()) {
|
||||
Bundle routerSavedState = savedPages.get(position);
|
||||
|
||||
if (routerSavedState != null) {
|
||||
router.restoreInstanceState(routerSavedState);
|
||||
savedPages.remove(position);
|
||||
}
|
||||
}
|
||||
|
||||
router.rebindIfNeeded();
|
||||
configureRouter(router, position);
|
||||
|
||||
if (router != primaryRouter) {
|
||||
for (RouterTransaction transaction : router.getBackstack()) {
|
||||
transaction.controller().setOptionsMenuHidden(true);
|
||||
}
|
||||
}
|
||||
|
||||
visibleRouters.put(position, router);
|
||||
return router;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
Router router = (Router)object;
|
||||
|
||||
Bundle savedState = new Bundle();
|
||||
router.saveInstanceState(savedState);
|
||||
savedPages.put(position, savedState);
|
||||
|
||||
savedPageHistory.remove((Integer)position);
|
||||
savedPageHistory.add(position);
|
||||
|
||||
ensurePagesSaved();
|
||||
|
||||
host.removeChildRouter(router);
|
||||
|
||||
visibleRouters.remove(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryItem(ViewGroup container, int position, Object object) {
|
||||
Router router = (Router)object;
|
||||
if (router != primaryRouter) {
|
||||
if (primaryRouter != null) {
|
||||
for (RouterTransaction transaction : primaryRouter.getBackstack()) {
|
||||
transaction.controller().setOptionsMenuHidden(true);
|
||||
}
|
||||
}
|
||||
if (router != null) {
|
||||
for (RouterTransaction transaction : router.getBackstack()) {
|
||||
transaction.controller().setOptionsMenuHidden(false);
|
||||
}
|
||||
}
|
||||
primaryRouter = router;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
Router router = (Router)object;
|
||||
final List<RouterTransaction> backstack = router.getBackstack();
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (transaction.controller().getView() == view) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable saveState() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSparseParcelableArray(KEY_SAVED_PAGES, savedPages);
|
||||
bundle.putInt(KEY_MAX_PAGES_TO_STATE_SAVE, maxPagesToStateSave);
|
||||
bundle.putIntegerArrayList(KEY_SAVE_PAGE_HISTORY, savedPageHistory);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState(Parcelable state, ClassLoader loader) {
|
||||
Bundle bundle = (Bundle)state;
|
||||
if (state != null) {
|
||||
savedPages = bundle.getSparseParcelableArray(KEY_SAVED_PAGES);
|
||||
maxPagesToStateSave = bundle.getInt(KEY_MAX_PAGES_TO_STATE_SAVE);
|
||||
savedPageHistory = bundle.getIntegerArrayList(KEY_SAVE_PAGE_HISTORY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the already instantiated Router in the specified position or {@code null} if there
|
||||
* is no router associated with this position.
|
||||
*/
|
||||
@Nullable
|
||||
public Router getRouter(int position) {
|
||||
return visibleRouters.get(position);
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
SparseArray<Bundle> getSavedPages() {
|
||||
return savedPages;
|
||||
}
|
||||
|
||||
private void ensurePagesSaved() {
|
||||
while (savedPages.size() > maxPagesToStateSave) {
|
||||
int positionToRemove = savedPageHistory.remove(0);
|
||||
savedPages.remove(positionToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
private static String makeRouterName(int viewId, long id) {
|
||||
return viewId + ":" + id;
|
||||
}
|
||||
|
||||
}
|
@ -2,21 +2,14 @@ package eu.kanade.tachiyomi.ui.catalogue
|
||||
|
||||
import android.view.View
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.util.LocaleHelper
|
||||
import kotlinx.android.synthetic.main.catalogue_main_controller_card.*
|
||||
import java.util.*
|
||||
|
||||
class LangHolder(view: View, adapter: FlexibleAdapter<*>) :
|
||||
BaseFlexibleViewHolder(view, adapter, true) {
|
||||
|
||||
fun bind(item: LangItem) {
|
||||
title.text = when {
|
||||
item.code == "" -> itemView.context.getString(R.string.other_source)
|
||||
else -> {
|
||||
val locale = Locale(item.code)
|
||||
locale.getDisplayName(locale).capitalize()
|
||||
}
|
||||
}
|
||||
title.text = LocaleHelper.getDisplayName(item.code, itemView.context)
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.online.LoginSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.setting.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.LocaleHelper
|
||||
import eu.kanade.tachiyomi.widget.preference.LoginPreference
|
||||
import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog
|
||||
import kotlinx.android.synthetic.main.extension_detail_controller.*
|
||||
@ -57,12 +58,12 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
val extension = presenter.extension
|
||||
val extension = presenter.extension ?: return
|
||||
val context = view.context
|
||||
|
||||
extension_title.text = extension.name
|
||||
extension_version.text = context.getString(R.string.ext_version_info, extension.versionName)
|
||||
extension_lang.text = context.getString(R.string.ext_language_info, extension.getLocalizedLang(context))
|
||||
extension_lang.text = context.getString(R.string.ext_language_info, LocaleHelper.getDisplayName(extension.lang, context))
|
||||
extension_pkg.text = extension.pkgName
|
||||
extension.getApplicationIcon(context)?.let { extension_icon.setImageDrawable(it) }
|
||||
extension_uninstall_button.clicks().subscribeUntilDestroy {
|
||||
@ -122,8 +123,8 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
val dataStore = SharedPreferencesDataStore(/*if (source is HttpSource) {
|
||||
source.preferences
|
||||
} else {*/
|
||||
context.getSharedPreferences("source_${source.id}", Context.MODE_PRIVATE)
|
||||
/*}*/)
|
||||
context.getSharedPreferences("source_${source.id}", Context.MODE_PRIVATE)
|
||||
/*}*/)
|
||||
|
||||
if (source is ConfigurableSource) {
|
||||
if (multiSource) {
|
||||
|
@ -12,7 +12,7 @@ class ExtensionDetailsPresenter(
|
||||
private val extensionManager: ExtensionManager = Injekt.get()
|
||||
) : BasePresenter<ExtensionDetailsController>() {
|
||||
|
||||
val extension = extensionManager.installedExtensions.first { it.pkgName == pkgName }
|
||||
val extension = extensionManager.installedExtensions.find { it.pkgName == pkgName }
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
@ -33,6 +33,7 @@ class ExtensionDetailsPresenter(
|
||||
}
|
||||
|
||||
fun uninstallExtension() {
|
||||
val extension = extension ?: return
|
||||
extensionManager.uninstallExtension(extension.pkgName)
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.ui.base.holder.SlicedHolder
|
||||
import eu.kanade.tachiyomi.util.LocaleHelper
|
||||
import io.github.mthli.slice.Slice
|
||||
import kotlinx.android.synthetic.main.extension_card_item.*
|
||||
|
||||
@ -35,7 +36,7 @@ class ExtensionHolder(view: View, override val adapter: ExtensionAdapter) :
|
||||
ext_title.text = extension.name
|
||||
version.text = extension.versionName
|
||||
lang.text = if (extension !is Extension.Untrusted) {
|
||||
extension.getLocalizedLang(itemView.context)
|
||||
LocaleHelper.getDisplayName(extension.lang, itemView.context)
|
||||
} else {
|
||||
itemView.context.getString(R.string.ext_untrusted).toUpperCase()
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ open class ExtensionPresenter(
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
extensionManager.findAvailableExtensions()
|
||||
bindToExtensionsObservable()
|
||||
}
|
||||
|
||||
|
@ -3,21 +3,7 @@ package eu.kanade.tachiyomi.ui.extension
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.Drawable
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import java.util.*
|
||||
|
||||
fun Extension.getLocalizedLang(context: Context): String {
|
||||
return when (lang) {
|
||||
null -> ""
|
||||
"" -> context.getString(R.string.other_source)
|
||||
"all" -> context.getString(R.string.all_lang)
|
||||
else -> {
|
||||
val locale = Locale(lang)
|
||||
locale.getDisplayName(locale).capitalize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Extension.getApplicationIcon(context: Context): Drawable? {
|
||||
return try {
|
||||
|
@ -191,7 +191,10 @@ class MainActivity : BaseActivity() {
|
||||
SHORTCUT_RECENTLY_UPDATED -> setSelectedDrawerItem(R.id.nav_drawer_recent_updates)
|
||||
SHORTCUT_RECENTLY_READ -> setSelectedDrawerItem(R.id.nav_drawer_recently_read)
|
||||
SHORTCUT_CATALOGUES -> setSelectedDrawerItem(R.id.nav_drawer_catalogues)
|
||||
SHORTCUT_MANGA -> router.setRoot(RouterTransaction.with(MangaController(intent.extras)))
|
||||
SHORTCUT_MANGA -> {
|
||||
val extras = intent.extras ?: return false
|
||||
router.setRoot(RouterTransaction.with(MangaController(extras)))
|
||||
}
|
||||
SHORTCUT_DOWNLOADS -> {
|
||||
if (router.backstack.none { it.controller() is DownloadController }) {
|
||||
setSelectedDrawerItem(R.id.nav_drawer_downloads)
|
||||
|
@ -13,6 +13,7 @@ import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.support.RouterPagerAdapter
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.kanade.tachiyomi.R
|
||||
@ -21,8 +22,9 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.base.controller.*
|
||||
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.RxController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersController
|
||||
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController
|
||||
import eu.kanade.tachiyomi.ui.manga.track.TrackController
|
||||
@ -37,7 +39,7 @@ import java.util.*
|
||||
class MangaController : RxController, TabbedController {
|
||||
|
||||
constructor(manga: Manga?, fromCatalogue: Boolean = false) : super(Bundle().apply {
|
||||
putLong(MANGA_EXTRA, manga?.id!!)
|
||||
putLong(MANGA_EXTRA, manga?.id ?: 0)
|
||||
putBoolean(FROM_CATALOGUE_EXTRA, fromCatalogue)
|
||||
}) {
|
||||
this.manga = manga
|
||||
|
@ -387,7 +387,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
|
||||
val chapters = if (presenter.sortDescending()) adapter.items.reversed() else adapter.items
|
||||
val chapterPos = chapters.indexOf(chapter)
|
||||
if (chapterPos != -1) {
|
||||
presenter.markChaptersRead(chapters.take(chapterPos), true)
|
||||
markAsRead(chapters.take(chapterPos))
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,8 +32,8 @@ class SettingsGeneralController : SettingsController() {
|
||||
listPreference {
|
||||
key = Keys.lang
|
||||
titleRes = R.string.pref_language
|
||||
entryValues = arrayOf("", "ar", "bg", "de", "en", "es", "fr", "id", "it", "lv", "ms",
|
||||
"nl", "pl", "pt", "pt-BR", "ru", "vi")
|
||||
entryValues = arrayOf("", "ar", "bg", "bn", "de", "en", "es", "fr", "hi", "hu", "id",
|
||||
"it", "ja", "ko", "lv", "ms", "nl", "pl", "pt", "pt-BR", "ro", "ru", "vi")
|
||||
entries = entryValues.map { value ->
|
||||
val locale = LocaleHelper.getLocaleFromString(value.toString())
|
||||
locale?.getDisplayName(locale)?.capitalize() ?:
|
||||
@ -246,4 +246,4 @@ class SettingsGeneralController : SettingsController() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.LoginSource
|
||||
import eu.kanade.tachiyomi.util.LocaleHelper
|
||||
import eu.kanade.tachiyomi.widget.preference.LoginCheckBoxPreference
|
||||
import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog
|
||||
import eu.kanade.tachiyomi.widget.preference.SwitchPreferenceCategory
|
||||
@ -39,7 +40,7 @@ class SettingsSourcesController : SettingsController(),
|
||||
// Create a preference group and set initial state and change listener
|
||||
SwitchPreferenceCategory(context).apply {
|
||||
preferenceScreen.addPreference(this)
|
||||
title = Locale(lang).let { it.getDisplayLanguage(it).capitalize() }
|
||||
title = LocaleHelper.getDisplayName(lang, context)
|
||||
isPersistent = false
|
||||
if (lang in activeLangsCodes) {
|
||||
setChecked(true)
|
||||
|
@ -1,10 +1,12 @@
|
||||
package eu.kanade.tachiyomi.util
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.LocaleList
|
||||
import android.view.ContextThemeWrapper
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.*
|
||||
@ -45,10 +47,34 @@ object LocaleHelper {
|
||||
if (pref.isNullOrEmpty()) {
|
||||
return null
|
||||
}
|
||||
val parts = pref.split("_", "-")
|
||||
val lang = parts[0]
|
||||
val country = parts.getOrNull(1) ?: ""
|
||||
return Locale(lang, country)
|
||||
return getLocale(pref)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Display name of a string language code
|
||||
*/
|
||||
fun getDisplayName(lang: String?, context: Context): String {
|
||||
return when (lang) {
|
||||
null -> ""
|
||||
"" -> context.getString(R.string.other_source)
|
||||
"all" -> context.getString(R.string.all_lang)
|
||||
else -> {
|
||||
val locale = getLocale(lang)
|
||||
locale.getDisplayName(locale).capitalize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Return Locale from string language code
|
||||
|
||||
*/
|
||||
private fun getLocale(lang: String): Locale {
|
||||
val sp = lang.split("_", "-")
|
||||
return when (sp.size) {
|
||||
2 -> Locale(sp[0], sp[1])
|
||||
3 -> Locale(sp[0], sp[1], sp[2])
|
||||
else -> Locale(lang)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user