mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 06:17:57 +01:00 
			
		
		
		
	| @@ -134,4 +134,6 @@ class PreferencesHelper(context: Context) { | ||||
|  | ||||
|     fun automaticUpdates() = prefs.getBoolean(keys.automaticUpdates, false) | ||||
|  | ||||
|     fun hiddenCatalogues() = rxPrefs.getStringSet("hidden_catalogues", emptySet()) | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -16,6 +16,7 @@ import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.f2prateek.rx.preferences.Preference | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.source.online.LoginSource | ||||
| import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder | ||||
| import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment | ||||
| import eu.kanade.tachiyomi.ui.main.MainActivity | ||||
| @@ -45,7 +46,7 @@ class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleViewHold | ||||
|     /** | ||||
|      * Spinner shown in the toolbar to change the selected source. | ||||
|      */ | ||||
|     private lateinit var spinner: Spinner | ||||
|     private var spinner: Spinner? = null | ||||
|  | ||||
|     /** | ||||
|      * Adapter containing the list of manga from the catalogue. | ||||
| @@ -125,6 +126,14 @@ class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleViewHold | ||||
|     } | ||||
|  | ||||
|     override fun onViewCreated(view: View, savedState: Bundle?) { | ||||
|         // If the source list is empty or it only has unlogged sources, return to main screen. | ||||
|         val sources = presenter.sources | ||||
|         if (sources.isEmpty() || sources.all { it is LoginSource && !it.isLogged() }) { | ||||
|             context.toast(R.string.no_valid_sources) | ||||
|             activity.onBackPressed() | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         // Initialize adapter, scroll listener and recycler views | ||||
|         adapter = CatalogueAdapter(this) | ||||
|  | ||||
| @@ -166,7 +175,7 @@ class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleViewHold | ||||
|         val onItemSelected = IgnoreFirstSpinnerListener { position -> | ||||
|             val source = spinnerAdapter.getItem(position) | ||||
|             if (!presenter.isValidSource(source)) { | ||||
|                 spinner.setSelection(selectedIndex) | ||||
|                 spinner?.setSelection(selectedIndex) | ||||
|                 context.toast(R.string.source_requires_login) | ||||
|             } else if (source != presenter.source) { | ||||
|                 selectedIndex = position | ||||
| @@ -264,7 +273,7 @@ class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleViewHold | ||||
|         searchItem?.let { | ||||
|             if (it.isActionViewExpanded) it.collapseActionView() | ||||
|         } | ||||
|         toolbar.removeView(spinner) | ||||
|         spinner?.let { toolbar.removeView(it) } | ||||
|         super.onDestroyView() | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -21,6 +21,7 @@ import rx.schedulers.Schedulers | ||||
| import rx.subjects.PublishSubject | ||||
| import timber.log.Timber | ||||
| import uy.kohesive.injekt.injectLazy | ||||
| import java.util.NoSuchElementException | ||||
|  | ||||
| /** | ||||
|  * Presenter of [CatalogueFragment]. | ||||
| @@ -103,7 +104,11 @@ class CataloguePresenter : BasePresenter<CatalogueFragment>() { | ||||
|     override fun onCreate(savedState: Bundle?) { | ||||
|         super.onCreate(savedState) | ||||
|  | ||||
|         source = getLastUsedSource() | ||||
|         try { | ||||
|             source = getLastUsedSource() | ||||
|         } catch (error: NoSuchElementException) { | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         if (savedState != null) { | ||||
|             query = savedState.getString(CataloguePresenter::query.name, "") | ||||
| @@ -324,6 +329,7 @@ class CataloguePresenter : BasePresenter<CatalogueFragment>() { | ||||
|      */ | ||||
|     private fun getEnabledSources(): List<OnlineSource> { | ||||
|         val languages = prefs.enabledLanguages().getOrDefault() | ||||
|         val hiddenCatalogues = prefs.hiddenCatalogues().getOrDefault() | ||||
|  | ||||
|         // Ensure at least one language | ||||
|         if (languages.isEmpty()) { | ||||
| @@ -332,6 +338,7 @@ class CataloguePresenter : BasePresenter<CatalogueFragment>() { | ||||
|  | ||||
|         return sourceManager.getOnlineSources() | ||||
|                 .filter { it.lang.code in languages } | ||||
|                 .filterNot { it.id.toString() in hiddenCatalogues } | ||||
|                 .sortedBy { "(${it.lang.code}) ${it.name}" } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,21 +1,19 @@ | ||||
| package eu.kanade.tachiyomi.ui.setting | ||||
|  | ||||
| import android.content.Intent | ||||
| import android.graphics.drawable.Drawable | ||||
| import android.os.Bundle | ||||
| import android.support.v7.preference.Preference | ||||
| import android.support.v7.preference.PreferenceGroup | ||||
| import android.support.v7.preference.XpPreferenceFragment | ||||
| import android.view.View | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.preference.getOrDefault | ||||
| import eu.kanade.tachiyomi.data.source.Source | ||||
| import eu.kanade.tachiyomi.data.source.SourceManager | ||||
| import eu.kanade.tachiyomi.data.source.getLanguages | ||||
| import eu.kanade.tachiyomi.data.source.online.LoginSource | ||||
| import eu.kanade.tachiyomi.util.plusAssign | ||||
| import eu.kanade.tachiyomi.widget.preference.LoginPreference | ||||
| import eu.kanade.tachiyomi.widget.preference.LoginCheckBoxPreference | ||||
| import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog | ||||
| import net.xpece.android.support.preference.MultiSelectListPreference | ||||
| import eu.kanade.tachiyomi.widget.preference.SwitchPreferenceCategory | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| class SettingsSourcesFragment : SettingsFragment() { | ||||
| @@ -32,59 +30,105 @@ class SettingsSourcesFragment : SettingsFragment() { | ||||
|  | ||||
|     private val preferences: PreferencesHelper by injectLazy() | ||||
|  | ||||
|     private val sourceManager: SourceManager by injectLazy() | ||||
|     private val onlineSources by lazy { Injekt.get<SourceManager>().getOnlineSources() } | ||||
|  | ||||
|     val languagesPref by lazy { findPreference("pref_source_languages") as MultiSelectListPreference } | ||||
|  | ||||
|     val sourcesPref by lazy { findPreference("pref_sources") as PreferenceGroup } | ||||
|     override fun setDivider(divider: Drawable?) { | ||||
|         super.setDivider(null) | ||||
|     } | ||||
|  | ||||
|     override fun onViewCreated(view: View, savedState: Bundle?) { | ||||
|         super.onViewCreated(view, savedState) | ||||
|  | ||||
|         // Remove dummy preference | ||||
|         preferenceScreen.removeAll() | ||||
|  | ||||
|         // Get the list of active language codes. | ||||
|         val activeLangsCodes = preferences.enabledLanguages().getOrDefault() | ||||
|  | ||||
|         // Get the list of languages ordered by name. | ||||
|         val langs = getLanguages().sortedBy { it.lang } | ||||
|  | ||||
|         val entryKeys = langs.map { it.code } | ||||
|         languagesPref.entries = langs.map { it.lang }.toTypedArray() | ||||
|         languagesPref.entryValues = entryKeys.toTypedArray() | ||||
|         languagesPref.values = preferences.enabledLanguages().getOrDefault() | ||||
|         // Order first by active languages, then inactive ones | ||||
|         val orderedLangs = langs.filter { it.code in activeLangsCodes } + | ||||
|                 langs.filterNot { it.code in activeLangsCodes } | ||||
|  | ||||
|         subscriptions += preferences.enabledLanguages().asObservable() | ||||
|                 .subscribe { languages -> | ||||
|                     sourcesPref.removeAll() | ||||
|  | ||||
|                     val enabledSources = sourceManager.getOnlineSources() | ||||
|                             .filter { it.lang.code in languages } | ||||
|  | ||||
|                     for (source in enabledSources.filterIsInstance(LoginSource::class.java)) { | ||||
|                         val pref = createLoginSourceEntry(source) | ||||
|                         sourcesPref.addPreference(pref) | ||||
|                     } | ||||
|  | ||||
|                     // Hide category if it doesn't have any child | ||||
|                     sourcesPref.isVisible = sourcesPref.preferenceCount > 0 | ||||
|         orderedLangs.forEach { lang -> | ||||
|             // Create a preference group and set initial state and change listener | ||||
|             SwitchPreferenceCategory(context).apply { | ||||
|                 preferenceScreen.addPreference(this) | ||||
|                 title = lang.lang | ||||
|                 isPersistent = false | ||||
|                 if (lang.code in activeLangsCodes) { | ||||
|                     setChecked(true) | ||||
|                     addLanguageSources(this) | ||||
|                 } | ||||
|  | ||||
|                 setOnPreferenceChangeListener { preference, any -> | ||||
|                     val checked = any as Boolean | ||||
|                     val current = preferences.enabledLanguages().getOrDefault() | ||||
|                     if (!checked) { | ||||
|                         preferences.enabledLanguages().set(current - lang.code) | ||||
|                         removeAll() | ||||
|                     } else { | ||||
|                         preferences.enabledLanguages().set(current + lang.code) | ||||
|                         addLanguageSources(this) | ||||
|                     } | ||||
|                     true | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun createLoginSourceEntry(source: Source): Preference { | ||||
|         return LoginPreference(preferenceManager.context).apply { | ||||
|             key = preferences.keys.sourceUsername(source.id) | ||||
|             title = source.toString() | ||||
|     /** | ||||
|      * Adds the source list for the given group (language). | ||||
|      * | ||||
|      * @param group the language category. | ||||
|      */ | ||||
|     private fun addLanguageSources(group: SwitchPreferenceCategory) { | ||||
|         val sources = onlineSources.filter { it.lang.lang == group.title }.sortedBy { it.name } | ||||
|         val hiddenCatalogues = preferences.hiddenCatalogues().getOrDefault() | ||||
|  | ||||
|         sources.forEach { source -> | ||||
|             val sourcePreference = LoginCheckBoxPreference(context, source).apply { | ||||
|                 val id = source.id.toString() | ||||
|                 title = source.name | ||||
|                 key = getSourceKey(source.id) | ||||
|                 isPersistent = false | ||||
|                 isChecked = id !in hiddenCatalogues | ||||
|  | ||||
|                 setOnPreferenceChangeListener { preference, any -> | ||||
|                     val checked = any as Boolean | ||||
|                     val current = preferences.hiddenCatalogues().getOrDefault() | ||||
|  | ||||
|                     preferences.hiddenCatalogues().set(if (checked) | ||||
|                         current - id | ||||
|                     else | ||||
|                         current + id) | ||||
|  | ||||
|                     true | ||||
|                 } | ||||
|  | ||||
|                 setOnLoginClickListener { | ||||
|                     val fragment = SourceLoginDialog.newInstance(source) | ||||
|                     fragment.setTargetFragment(this@SettingsSourcesFragment, SOURCE_CHANGE_REQUEST) | ||||
|                     fragment.show(fragmentManager, null) | ||||
|                 } | ||||
|  | ||||
|             setOnPreferenceClickListener { | ||||
|                 val fragment = SourceLoginDialog.newInstance(source) | ||||
|                 fragment.setTargetFragment(this@SettingsSourcesFragment, SOURCE_CHANGE_REQUEST) | ||||
|                 fragment.show(fragmentManager, null) | ||||
|                 true | ||||
|             } | ||||
|  | ||||
|             group.addPreference(sourcePreference) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { | ||||
|         if (requestCode == SOURCE_CHANGE_REQUEST) { | ||||
|             val pref = findPreference(preferences.keys.sourceUsername(resultCode)) as? LoginPreference | ||||
|             val pref = findPreference(getSourceKey(resultCode)) as? LoginCheckBoxPreference | ||||
|             pref?.notifyChanged() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun getSourceKey(sourceId: Int): String { | ||||
|         return "source_$sourceId" | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,56 @@ | ||||
| package eu.kanade.tachiyomi.widget.preference | ||||
|  | ||||
| import android.content.Context | ||||
| import android.graphics.Color | ||||
| import android.support.v7.preference.PreferenceViewHolder | ||||
| import android.util.AttributeSet | ||||
| import android.view.View | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.source.online.LoginSource | ||||
| import eu.kanade.tachiyomi.data.source.online.OnlineSource | ||||
| import eu.kanade.tachiyomi.util.setVectorCompat | ||||
| import kotlinx.android.synthetic.main.pref_item_source.view.* | ||||
| import net.xpece.android.support.preference.CheckBoxPreference | ||||
|  | ||||
| class LoginCheckBoxPreference @JvmOverloads constructor( | ||||
|         context: Context, | ||||
|         val source: OnlineSource, | ||||
|         attrs: AttributeSet? = null | ||||
| ) : CheckBoxPreference(context, attrs) { | ||||
|  | ||||
|     init { | ||||
|         layoutResource = R.layout.pref_item_source | ||||
|     } | ||||
|  | ||||
|     private var onLoginClick: () -> Unit = {} | ||||
|  | ||||
|     override fun onBindViewHolder(holder: PreferenceViewHolder) { | ||||
|         super.onBindViewHolder(holder) | ||||
|         val loginFrame = holder.itemView.login_frame | ||||
|         if (source is LoginSource) { | ||||
|             val tint = if (source.isLogged()) | ||||
|                 Color.argb(255, 76, 175, 80) | ||||
|             else | ||||
|                 Color.argb(97, 0, 0, 0) | ||||
|  | ||||
|             holder.itemView.login.setVectorCompat(R.drawable.ic_account_circle_black_24dp, tint) | ||||
|  | ||||
|             loginFrame.visibility = View.VISIBLE | ||||
|             loginFrame.setOnClickListener { | ||||
|                 onLoginClick() | ||||
|             } | ||||
|         } else { | ||||
|             loginFrame.visibility = View.GONE | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun setOnLoginClickListener(block: () -> Unit) { | ||||
|         onLoginClick = block | ||||
|     } | ||||
|  | ||||
|     // Make method public | ||||
|     override public fun notifyChanged() { | ||||
|         super.notifyChanged() | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,137 @@ | ||||
| package eu.kanade.tachiyomi.widget.preference | ||||
|  | ||||
| import android.annotation.TargetApi | ||||
| import android.content.Context | ||||
| import android.content.res.TypedArray | ||||
| import android.os.Build | ||||
| import android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH | ||||
| import android.support.v7.preference.PreferenceViewHolder | ||||
| import android.support.v7.widget.SwitchCompat | ||||
| import android.util.AttributeSet | ||||
| import android.view.View | ||||
| import android.widget.Checkable | ||||
| import android.widget.CompoundButton | ||||
| import android.widget.Switch | ||||
| import eu.kanade.tachiyomi.util.getResourceColor | ||||
| import net.xpece.android.support.preference.PreferenceCategory | ||||
| import net.xpece.android.support.preference.R | ||||
|  | ||||
| class SwitchPreferenceCategory @JvmOverloads constructor( | ||||
|         context: Context, | ||||
|         attrs: AttributeSet? = null) | ||||
| : PreferenceCategory( | ||||
|         context, | ||||
|         attrs, | ||||
|         R.attr.switchPreferenceCompatStyle, | ||||
|         R.style.Preference_Material_SwitchPreferenceCompat), | ||||
| CompoundButton.OnCheckedChangeListener { | ||||
|  | ||||
|     init { | ||||
|         setTitleTextColor(context.theme.getResourceColor(R.attr.colorAccent)) | ||||
|     } | ||||
|  | ||||
|     private var mChecked = false | ||||
|  | ||||
|     private var mCheckedSet = false | ||||
|  | ||||
|     override fun onBindViewHolder(holder: PreferenceViewHolder) { | ||||
|         super.onBindViewHolder(holder) | ||||
|         syncSwitchView(holder) | ||||
|     } | ||||
|  | ||||
|     private fun syncSwitchView(holder: PreferenceViewHolder) { | ||||
|         val switchView = holder.findViewById(R.id.switchWidget) | ||||
|         syncSwitchView(switchView) | ||||
|     } | ||||
|  | ||||
|     @TargetApi(ICE_CREAM_SANDWICH) | ||||
|     private fun syncSwitchView(view: View) { | ||||
|         if (view is Checkable) { | ||||
|             val isChecked = view.isChecked | ||||
|             if (isChecked == mChecked) return | ||||
|  | ||||
|             if (view is SwitchCompat) { | ||||
|                 view.setOnCheckedChangeListener(null) | ||||
|             } else if (NATIVE_SWITCH_CAPABLE && view is Switch) { | ||||
|                 view.setOnCheckedChangeListener(null) | ||||
|             } | ||||
|  | ||||
|             view.toggle() | ||||
|  | ||||
|             if (view is SwitchCompat) { | ||||
|                 view.setOnCheckedChangeListener(this) | ||||
|             } else if (NATIVE_SWITCH_CAPABLE && view is Switch) { | ||||
|                 view.setOnCheckedChangeListener(this) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { | ||||
|         if (!callChangeListener(isChecked)) { | ||||
|             buttonView.isChecked = !isChecked | ||||
|         } else { | ||||
|             setChecked(isChecked) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onClick() { | ||||
|         super.onClick() | ||||
|  | ||||
|         val newValue = !isChecked() | ||||
|         if (callChangeListener(newValue)) { | ||||
|             setChecked(newValue) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the checked state and saves it to the [SharedPreferences]. | ||||
|      * | ||||
|      * @param checked The checked state. | ||||
|      */ | ||||
|     fun setChecked(checked: Boolean) { | ||||
|         // Always persist/notify the first time; don't assume the field's default of false. | ||||
|         val changed = mChecked != checked | ||||
|         if (changed || !mCheckedSet) { | ||||
|             mChecked = checked | ||||
|             mCheckedSet = true | ||||
|             persistBoolean(checked) | ||||
|             if (changed) { | ||||
|                 notifyDependencyChange(shouldDisableDependents()) | ||||
|                 notifyChanged() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the checked state. | ||||
|      * | ||||
|      * @return The checked state. | ||||
|      */ | ||||
|     fun isChecked(): Boolean { | ||||
|         return mChecked | ||||
|     } | ||||
|  | ||||
|     override fun isEnabled(): Boolean { | ||||
|         return true | ||||
|     } | ||||
|  | ||||
|     override fun shouldDisableDependents(): Boolean { | ||||
|         return false | ||||
|     } | ||||
|  | ||||
|     override fun onGetDefaultValue(a: TypedArray, index: Int): Any { | ||||
|         return a.getBoolean(index, false) | ||||
|     } | ||||
|  | ||||
|     override fun onSetInitialValue(restoreValue: Boolean, defaultValue: Any?) { | ||||
|         setChecked(if (restoreValue) | ||||
|             getPersistedBoolean(mChecked) | ||||
|         else | ||||
|             defaultValue as Boolean) | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         private val NATIVE_SWITCH_CAPABLE = Build.VERSION.SDK_INT >= ICE_CREAM_SANDWICH | ||||
|     } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user