mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 22:37:56 +01: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