Drop AppCompat

This commit is contained in:
kitsunyan
2020-06-25 23:02:28 +03:00
parent 41d5544bc8
commit b646259f5d
36 changed files with 496 additions and 240 deletions
+2 -2
View File
@@ -116,8 +116,8 @@ repositories {
dependencies { dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:' + versions.kotlin implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:' + versions.kotlin
implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.fragment:fragment:1.2.5'
implementation 'com.google.android.material:material:1.1.0' implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation 'com.squareup.okhttp3:okhttp:4.7.2' implementation 'com.squareup.okhttp3:okhttp:4.7.2'
implementation 'io.reactivex.rxjava3:rxjava:3.0.4' implementation 'io.reactivex.rxjava3:rxjava:3.0.4'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0' implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
@@ -2,7 +2,6 @@ package nya.kitsunyan.foxydroid.content
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.subjects.PublishSubject import io.reactivex.rxjava3.subjects.PublishSubject
import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.R
@@ -17,7 +16,7 @@ object Preferences {
Key.Theme, Key.UpdateNotify, Key.UpdateUnstable).map { Pair(it.name, it) }.toMap() Key.Theme, Key.UpdateNotify, Key.UpdateUnstable).map { Pair(it.name, it) }.toMap()
fun init(context: Context) { fun init(context: Context) {
preferences = PreferenceManager.getDefaultSharedPreferences(context) preferences = context.getSharedPreferences("${context.packageName}_preferences", Context.MODE_PRIVATE)
preferences.registerOnSharedPreferenceChangeListener { _, keyString -> keys[keyString]?.let(subject::onNext) } preferences.registerOnSharedPreferenceChangeListener { _, keyString -> keys[keyString]?.let(subject::onNext) }
} }
@@ -1,5 +1,6 @@
package nya.kitsunyan.foxydroid.screen package nya.kitsunyan.foxydroid.screen
import android.app.AlertDialog
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.graphics.PorterDuff import android.graphics.PorterDuff
@@ -17,8 +18,7 @@ import android.view.ViewGroup
import android.widget.EditText import android.widget.EditText
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AlertDialog import android.widget.Toolbar
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
@@ -1,11 +1,11 @@
package nya.kitsunyan.foxydroid.screen package nya.kitsunyan.foxydroid.screen
import android.app.AlertDialog
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Parcel import android.os.Parcel
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.R
@@ -1,38 +1,56 @@
package nya.kitsunyan.foxydroid.screen package nya.kitsunyan.foxydroid.screen
import android.app.AlertDialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.InputFilter import android.text.InputFilter
import android.text.InputType import android.text.InputType
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager
import android.widget.EditText
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.appcompat.widget.Toolbar import android.widget.LinearLayout
import androidx.preference.EditTextPreference import android.widget.ScrollView
import androidx.preference.ListPreference import android.widget.Switch
import androidx.preference.Preference import android.widget.TextView
import androidx.preference.PreferenceCategory import android.widget.Toolbar
import androidx.preference.PreferenceFragmentCompat import androidx.fragment.app.DialogFragment
import androidx.preference.PreferenceGroup import androidx.fragment.app.Fragment
import androidx.preference.SwitchPreference
import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.disposables.Disposable
import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.R
import nya.kitsunyan.foxydroid.content.Preferences import nya.kitsunyan.foxydroid.content.Preferences
import nya.kitsunyan.foxydroid.utility.extension.resources.*
class PreferencesFragment: PreferenceFragmentCompat() { class PreferencesFragment: Fragment() {
private val preferences = mutableMapOf<Preferences.Key<*>, Preference<*>>()
private var disposable: Disposable? = null private var disposable: Disposable? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val view = inflater.inflate(R.layout.fragment, container, false) return inflater.inflate(R.layout.fragment, container, false)
val content = view.findViewById<FrameLayout>(R.id.fragment_content)
val child = super.onCreateView(LayoutInflater.from(content.context), content, savedInstanceState)
content.addView(child, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
return view
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
preferenceScreen = preferenceManager.createPreferenceScreen(requireContext()) super.onViewCreated(view, savedInstanceState)
preferenceScreen.addCategory(getString(R.string.updates)).apply {
val toolbar = view.findViewById<Toolbar>(R.id.toolbar)
screenActivity.onFragmentViewCreated(toolbar)
toolbar.setTitle(R.string.preferences)
val content = view.findViewById<FrameLayout>(R.id.fragment_content)
val scroll = ScrollView(content.context)
scroll.id = R.id.preferences_list
scroll.isFillViewport = true
content.addView(scroll, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
val scrollLayout = FrameLayout(content.context)
scroll.addView(scrollLayout, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
val preferences = LinearLayout(scrollLayout.context)
preferences.orientation = LinearLayout.VERTICAL
scrollLayout.addView(preferences, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
preferences.addCategory(getString(R.string.updates)) {
addEnumeration(Preferences.Key.AutoSync, getString(R.string.sync_repositories_automatically)) { addEnumeration(Preferences.Key.AutoSync, getString(R.string.sync_repositories_automatically)) {
when (it) { when (it) {
Preferences.AutoSync.Never -> getString(R.string.never) Preferences.AutoSync.Never -> getString(R.string.never)
@@ -45,7 +63,7 @@ class PreferencesFragment: PreferenceFragmentCompat() {
addSwitch(Preferences.Key.UpdateUnstable, getString(R.string.unstable_updates), addSwitch(Preferences.Key.UpdateUnstable, getString(R.string.unstable_updates),
getString(R.string.unstable_updates_summary)) getString(R.string.unstable_updates_summary))
} }
preferenceScreen.addCategory(getString(R.string.proxy)).apply { preferences.addCategory(getString(R.string.proxy)) {
addEnumeration(Preferences.Key.ProxyType, getString(R.string.proxy_type)) { addEnumeration(Preferences.Key.ProxyType, getString(R.string.proxy_type)) {
when (it) { when (it) {
is Preferences.ProxyType.Direct -> getString(R.string.no_proxy) is Preferences.ProxyType.Direct -> getString(R.string.no_proxy)
@@ -56,7 +74,7 @@ class PreferencesFragment: PreferenceFragmentCompat() {
addEditString(Preferences.Key.ProxyHost, getString(R.string.proxy_host)) addEditString(Preferences.Key.ProxyHost, getString(R.string.proxy_host))
addEditInt(Preferences.Key.ProxyPort, getString(R.string.proxy_port), 1 .. 65535) addEditInt(Preferences.Key.ProxyPort, getString(R.string.proxy_port), 1 .. 65535)
} }
preferenceScreen.addCategory(getString(R.string.other)).apply { preferences.addCategory(getString(R.string.other)) {
addEnumeration(Preferences.Key.Theme, getString(R.string.theme)) { addEnumeration(Preferences.Key.Theme, getString(R.string.theme)) {
when (it) { when (it) {
is Preferences.Theme.Light -> getString(R.string.light) is Preferences.Theme.Light -> getString(R.string.light)
@@ -66,14 +84,6 @@ class PreferencesFragment: PreferenceFragmentCompat() {
addSwitch(Preferences.Key.IncompatibleVersions, getString(R.string.incompatible_versions), addSwitch(Preferences.Key.IncompatibleVersions, getString(R.string.incompatible_versions),
getString(R.string.incompatible_versions_summary)) getString(R.string.incompatible_versions_summary))
} }
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val toolbar = view.findViewById<Toolbar>(R.id.toolbar)
screenActivity.onFragmentViewCreated(toolbar)
toolbar.setTitle(R.string.preferences)
disposable = Preferences.observable.subscribe(this::updatePreference) disposable = Preferences.observable.subscribe(this::updatePreference)
updatePreference(null) updatePreference(null)
@@ -82,75 +92,107 @@ class PreferencesFragment: PreferenceFragmentCompat() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
preferences.clear()
disposable?.dispose() disposable?.dispose()
disposable = null disposable = null
} }
private fun updatePreference(key: Preferences.Key<*>?) { private fun updatePreference(key: Preferences.Key<*>?) {
if (key != null) {
preferences[key]?.update()
}
if (key == null || key == Preferences.Key.ProxyType) { if (key == null || key == Preferences.Key.ProxyType) {
val enabled = when (Preferences[Preferences.Key.ProxyType]) { val enabled = when (Preferences[Preferences.Key.ProxyType]) {
is Preferences.ProxyType.Direct -> false is Preferences.ProxyType.Direct -> false
is Preferences.ProxyType.Http, is Preferences.ProxyType.Socks -> true is Preferences.ProxyType.Http, is Preferences.ProxyType.Socks -> true
} }
findPreference<Preference>(Preferences.Key.ProxyHost.name)!!.isEnabled = enabled preferences[Preferences.Key.ProxyHost]?.setEnabled(enabled)
findPreference<Preference>(Preferences.Key.ProxyPort.name)!!.isEnabled = enabled preferences[Preferences.Key.ProxyPort]?.setEnabled(enabled)
} }
if (key == Preferences.Key.Theme) { if (key == Preferences.Key.Theme) {
requireActivity().recreate() requireActivity().recreate()
} }
} }
private fun PreferenceGroup.addCategory(title: String): PreferenceCategory { private fun LinearLayout.addDivider(full: Boolean): View {
val preference = PreferenceCategory(context) val divider = View(context)
preference.isIconSpaceReserved = false divider.background = context.getDrawableFromAttr(android.R.attr.listDivider)
preference.title = title addView(divider, LinearLayout.LayoutParams.MATCH_PARENT, divider.background.intrinsicHeight)
addPreference(preference) if (!full) {
(divider.layoutParams as LinearLayout.LayoutParams).apply {
marginStart = divider.resources.sizeScaled(16)
}
}
return divider
}
private fun LinearLayout.addCategory(title: String, callback: LinearLayout.() -> Unit) {
val text = TextView(context)
text.typeface = TypefaceExtra.medium
text.setTextSizeScaled(14)
text.setTextColor(text.context.getColorFromAttr(android.R.attr.colorAccent))
text.text = title
resources.sizeScaled(16).let { text.setPadding(it, it, it, 0) }
addView(text, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
callback()
val divider = addDivider(true)
// Negative margin for last divider
(layoutParams as ViewGroup.MarginLayoutParams).bottomMargin = -divider.layoutParams.height
}
private fun <T> LinearLayout.addPreference(key: Preferences.Key<T>, title: String,
summaryProvider: () -> String, dialogProvider: ((Context) -> AlertDialog)?): Preference<T> {
if (childCount > 0 && getChildAt(childCount - 1) !is TextView) {
addDivider(false)
}
val preference = Preference(key, this@PreferencesFragment, this, title, summaryProvider, dialogProvider)
preferences[key] = preference
return preference return preference
} }
private fun PreferenceGroup.addSwitch(key: Preferences.Key<Boolean>, title: String, summary: String?) { private fun LinearLayout.addSwitch(key: Preferences.Key<Boolean>, title: String, summary: String) {
val preference = SwitchPreference(context) val preference = addPreference(key, title, { summary }, null)
preference.isIconSpaceReserved = false preference.check.visibility = View.VISIBLE
preference.title = title preference.view.setOnClickListener { Preferences[key] = !Preferences[key] }
preference.summary = summary preference.setCallback { preference.check.isChecked = Preferences[key] }
preference.key = key.name
preference.setDefaultValue(key.default.value)
addPreference(preference)
} }
private fun PreferenceGroup.addEditString(key: Preferences.Key<String>, title: String) { private fun <T> LinearLayout.addEdit(key: Preferences.Key<T>, title: String, valueToString: (T) -> String,
val preference = EditTextPreference(context) stringToValue: (String) -> T?, configureEdit: (EditText) -> Unit) {
preference.isIconSpaceReserved = false addPreference(key, title, { valueToString(Preferences[key]) }) {
preference.title = title val scroll = ScrollView(it)
preference.dialogTitle = title scroll.resources.sizeScaled(20).let { scroll.setPadding(it, 0, it, 0) }
preference.summaryProvider = Preference.SummaryProvider<EditTextPreference> { it.text } val edit = EditText(it)
preference.key = key.name configureEdit(edit)
preference.setDefaultValue(key.default.value) edit.id = android.R.id.edit
addPreference(preference) edit.setTextSizeScaled(16)
} edit.resources.sizeScaled(16).let { edit.setPadding(edit.paddingLeft, it, edit.paddingRight, it) }
edit.setText(valueToString(Preferences[key]))
private fun PreferenceGroup.addEditInt(key: Preferences.Key<Int>, title: String, range: IntRange?) { edit.hint = edit.text.toString()
val preference = object: EditTextPreference(context) { edit.setSelection(edit.text.length)
override fun persistString(value: String?): Boolean { edit.requestFocus()
val intValue = value.orEmpty().toIntOrNull() ?: key.default.value scroll.addView(edit, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
val result = persistInt(intValue) AlertDialog.Builder(it)
if (intValue.toString() != value) { .setTitle(title)
text = intValue.toString() .setView(scroll)
.setPositiveButton(R.string.ok) { _, _ ->
val value = stringToValue(edit.text.toString()) ?: key.default.value
post { Preferences[key] = value }
}
.setNegativeButton(R.string.cancel, null)
.create()
.apply {
window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
} }
return result
}
override fun onSetInitialValue(defaultValue: Any?) {
text = getPersistedInt((defaultValue as? Int) ?: key.default.value).toString()
}
} }
preference.isIconSpaceReserved = false }
preference.title = title
preference.dialogTitle = title private fun LinearLayout.addEditString(key: Preferences.Key<String>, title: String) {
preference.summaryProvider = Preference.SummaryProvider<EditTextPreference> { it.text } addEdit(key, title, { it }, { it }, { })
preference.key = key.name }
preference.setDefaultValue(key.default.value)
preference.setOnBindEditTextListener { private fun LinearLayout.addEditInt(key: Preferences.Key<Int>, title: String, range: IntRange?) {
addEdit(key, title, { it.toString() }, { it.toIntOrNull() }) {
it.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL it.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
if (range != null) { if (range != null) {
it.filters = arrayOf(InputFilter { source, start, end, dest, dstart, dend -> it.filters = arrayOf(InputFilter { source, start, end, dest, dstart, dend ->
@@ -160,23 +202,84 @@ class PreferencesFragment: PreferenceFragmentCompat() {
}) })
} }
} }
addPreference(preference)
} }
private fun <T: Preferences.Enumeration<T>> PreferenceGroup private fun <T: Preferences.Enumeration<T>> LinearLayout
.addEnumeration(key: Preferences.Key<T>, title: String, valueString: (T) -> String) { .addEnumeration(key: Preferences.Key<T>, title: String, valueToString: (T) -> String) {
val preference = ListPreference(context) addPreference(key, title, { valueToString(Preferences[key]) }) {
preference.isIconSpaceReserved = false val values = key.default.value.values
preference.title = title AlertDialog.Builder(it)
preference.dialogTitle = title .setTitle(title)
preference.summaryProvider = Preference.SummaryProvider<ListPreference> { p -> .setSingleChoiceItems(values.map(valueToString).toTypedArray(),
val index = p.entryValues.indexOfFirst { it == p.value } values.indexOf(Preferences[key])) { dialog, which ->
if (index >= 0) p.entries[index] else valueString(key.default.value) dialog.dismiss()
post { Preferences[key] = values[which] }
}
.setNegativeButton(R.string.cancel, null)
.create()
}
}
private class Preference<T>(private val key: Preferences.Key<T>,
fragment: Fragment, parent: ViewGroup, titleText: String,
private val summaryProvider: () -> String, private val dialogProvider: ((Context) -> AlertDialog)?) {
val view = parent.inflate(R.layout.preference_item)
val title = view.findViewById<TextView>(R.id.title)!!
val summary = view.findViewById<TextView>(R.id.summary)!!
val check = view.findViewById<Switch>(R.id.check)!!
private var callback: (() -> Unit)? = null
init {
title.text = titleText
parent.addView(view)
if (dialogProvider != null) {
view.setOnClickListener { PreferenceDialog(key.name)
.show(fragment.childFragmentManager, "${PreferenceDialog::class.java.name}.${key.name}") }
}
update()
}
fun setCallback(callback: () -> Unit) {
this.callback = callback
update()
}
fun setEnabled(enabled: Boolean) {
view.isEnabled = enabled
title.isEnabled = enabled
summary.isEnabled = enabled
check.isEnabled = enabled
}
fun update() {
summary.text = summaryProvider()
summary.visibility = if (summary.text.isNotEmpty()) View.VISIBLE else View.GONE
callback?.invoke()
}
fun createDialog(context: Context): AlertDialog {
return dialogProvider!!(context)
}
}
class PreferenceDialog(): DialogFragment() {
companion object {
private const val EXTRA_KEY = "key"
}
constructor(key: String): this() {
arguments = Bundle().apply {
putString(EXTRA_KEY, key)
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val preferences = (parentFragment as PreferencesFragment).preferences
val key = requireArguments().getString(EXTRA_KEY)!!
.let { name -> preferences.keys.find { it.name == name }!! }
val preference = preferences[key]!!
return preference.createDialog(requireContext())
} }
preference.key = key.name
preference.setDefaultValue(key.default.value.valueString)
preference.entryValues = key.default.value.values.map { it.valueString }.toTypedArray()
preference.entries = key.default.value.values.map(valueString).toTypedArray()
addPreference(preference)
} }
} }
@@ -33,11 +33,9 @@ import android.widget.FrameLayout
import android.widget.ImageView import android.widget.ImageView
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.ProgressBar import android.widget.ProgressBar
import android.widget.Switch
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.AppCompatTextView
import androidx.appcompat.widget.SwitchCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.core.text.util.LinkifyCompat import androidx.core.text.util.LinkifyCompat
@@ -106,12 +104,12 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
private enum class SectionType(val titleResId: Int, val colorAttrResId: Int) { private enum class SectionType(val titleResId: Int, val colorAttrResId: Int) {
ANTI_FEATURES(R.string.anti_features, R.attr.colorError), ANTI_FEATURES(R.string.anti_features, R.attr.colorError),
WHATS_NEW(R.string.whats_new, R.attr.colorAccent), WHATS_NEW(R.string.whats_new, android.R.attr.colorAccent),
LINKS(R.string.links, R.attr.colorAccent), LINKS(R.string.links, android.R.attr.colorAccent),
DONATE(R.string.donate, R.attr.colorAccent), DONATE(R.string.donate, android.R.attr.colorAccent),
PERMISSIONS(R.string.permissions, R.attr.colorAccent), PERMISSIONS(R.string.permissions, android.R.attr.colorAccent),
SCREENSHOTS(R.string.screenshots, R.attr.colorAccent), SCREENSHOTS(R.string.screenshots, android.R.attr.colorAccent),
RELEASES(R.string.releases, R.attr.colorAccent) RELEASES(R.string.releases, android.R.attr.colorAccent)
} }
internal enum class ExpandType { NOTHING, DESCRIPTION, WHATS_NEW, internal enum class ExpandType { NOTHING, DESCRIPTION, WHATS_NEW,
@@ -300,10 +298,13 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
val progressIcon: Drawable val progressIcon: Drawable
val defaultIcon: Drawable val defaultIcon: Drawable
val actionTintNormal = action.context.getColorFromAttr(R.attr.colorAccent) val actionTintNormal = action.context.getColorFromAttr(android.R.attr.colorAccent)
val actionTintCancel = action.context.getColorFromAttr(R.attr.colorError) val actionTintCancel = action.context.getColorFromAttr(R.attr.colorError)
init { init {
if (Android.sdk(22)) {
action.setTextColor(action.context.getColorFromAttr(android.R.attr.colorBackground))
}
val (progressIcon, defaultIcon) = Utils.getDefaultApplicationIcons(icon.context) val (progressIcon, defaultIcon) = Utils.getDefaultApplicationIcons(icon.context)
this.progressIcon = progressIcon this.progressIcon = progressIcon
this.defaultIcon = defaultIcon this.defaultIcon = defaultIcon
@@ -312,7 +313,7 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
private class SwitchViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { private class SwitchViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val title = itemView.findViewById<TextView>(R.id.title)!! val title = itemView.findViewById<TextView>(R.id.title)!!
val enabled = itemView.findViewById<SwitchCompat>(R.id.enabled)!! val enabled = itemView.findViewById<Switch>(R.id.enabled)!!
val statefulViews: Sequence<View> val statefulViews: Sequence<View>
get() = sequenceOf(itemView, title, enabled) get() = sequenceOf(itemView, title, enabled)
@@ -323,7 +324,7 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
val icon = itemView.findViewById<ImageView>(R.id.icon)!! val icon = itemView.findViewById<ImageView>(R.id.icon)!!
} }
private class ExpandViewHolder(context: Context): RecyclerView.ViewHolder(AppCompatTextView(context)) { private class ExpandViewHolder(context: Context): RecyclerView.ViewHolder(TextView(context)) {
val text: TextView val text: TextView
get() = itemView as TextView get() = itemView as TextView
@@ -331,8 +332,8 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
itemView as TextView itemView as TextView
itemView.typeface = TypefaceExtra.medium itemView.typeface = TypefaceExtra.medium
itemView.setTextSizeScaled(14) itemView.setTextSizeScaled(14)
itemView.setTextColor(itemView.context.getColorFromAttr(R.attr.colorAccent)) itemView.setTextColor(itemView.context.getColorFromAttr(android.R.attr.colorAccent))
itemView.background = itemView.context.getDrawableFromAttr(R.attr.selectableItemBackground) itemView.background = itemView.context.getDrawableFromAttr(android.R.attr.selectableItemBackground)
itemView.gravity = Gravity.CENTER itemView.gravity = Gravity.CENTER
itemView.isAllCaps = true itemView.isAllCaps = true
itemView.layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, itemView.layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT,
@@ -340,7 +341,7 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
} }
} }
private class TextViewHolder(context: Context): RecyclerView.ViewHolder(AppCompatTextView(context)) { private class TextViewHolder(context: Context): RecyclerView.ViewHolder(TextView(context)) {
val text: TextView val text: TextView
get() = itemView as TextView get() = itemView as TextView
@@ -423,12 +424,12 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
init { init {
itemView as FrameLayout itemView as FrameLayout
itemView.foreground = itemView.context.getDrawableFromAttr(R.attr.selectableItemBackground) itemView.foreground = itemView.context.getDrawableFromAttr(android.R.attr.selectableItemBackground)
val backgroundColor = itemView.context.getColorFromAttr(android.R.attr.colorBackground).defaultColor val backgroundColor = itemView.context.getColorFromAttr(android.R.attr.colorBackground).defaultColor
val accentColor = itemView.context.getColorFromAttr(R.attr.colorAccent).defaultColor val accentColor = itemView.context.getColorFromAttr(android.R.attr.colorAccent).defaultColor
val primaryColor = itemView.context.getColorFromAttr(android.R.attr.textColorPrimary).defaultColor val primaryColor = itemView.context.getColorFromAttr(android.R.attr.textColorPrimary).defaultColor
image = object: AppCompatImageView(context) { image = object: ImageView(context) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec) super.onMeasure(widthMeasureSpec, heightMeasureSpec)
setMeasuredDimension(measuredWidth, measuredWidth) setMeasuredDimension(measuredWidth, measuredWidth)
@@ -465,7 +466,7 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
init { init {
status.background = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, null).apply { status.background = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, null).apply {
setStatusActive = { active -> color = itemView.context.getColorFromAttr(if (active) setStatusActive = { active -> color = itemView.context.getColorFromAttr(if (active)
R.attr.colorAccent else android.R.attr.textColorSecondary) } android.R.attr.colorAccent else android.R.attr.textColorSecondary) }
cornerRadius = itemView.resources.sizeScaled(2).toFloat() cornerRadius = itemView.resources.sizeScaled(2).toFloat()
} }
} }
@@ -479,14 +480,14 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
itemView.orientation = LinearLayout.VERTICAL itemView.orientation = LinearLayout.VERTICAL
itemView.gravity = Gravity.CENTER itemView.gravity = Gravity.CENTER
itemView.resources.sizeScaled(20).let { itemView.setPadding(it, it, it, it) } itemView.resources.sizeScaled(20).let { itemView.setPadding(it, it, it, it) }
val title = AppCompatTextView(itemView.context) val title = TextView(itemView.context)
title.gravity = Gravity.CENTER title.gravity = Gravity.CENTER
title.typeface = TypefaceExtra.light title.typeface = TypefaceExtra.light
title.setTextColor(context.getColorFromAttr(android.R.attr.textColorPrimary)) title.setTextColor(context.getColorFromAttr(android.R.attr.textColorPrimary))
title.setTextSizeScaled(20) title.setTextSizeScaled(20)
title.setText(R.string.application_not_found) title.setText(R.string.application_not_found)
itemView.addView(title, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) itemView.addView(title, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
val packageName = AppCompatTextView(itemView.context) val packageName = TextView(itemView.context)
packageName.gravity = Gravity.CENTER packageName.gravity = Gravity.CENTER
packageName.setTextColor(context.getColorFromAttr(android.R.attr.textColorPrimary)) packageName.setTextColor(context.getColorFromAttr(android.R.attr.textColorPrimary))
packageName.setTextSizeScaled(16) packageName.setTextSizeScaled(16)
@@ -974,8 +975,10 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
if (action != null) { if (action != null) {
holder.action.setText(action.titleResId) holder.action.setText(action.titleResId)
} }
holder.action.backgroundTintList = if (action == Action.CANCEL) if (Android.sdk(22)) {
holder.actionTintCancel else holder.actionTintNormal holder.action.backgroundTintList = if (action == Action.CANCEL)
holder.actionTintCancel else holder.actionTintNormal
}
holder.statusLayout.visibility = if (status != null) View.VISIBLE else View.GONE holder.statusLayout.visibility = if (status != null) View.VISIBLE else View.GONE
if (status != null) { if (status != null) {
when (status) { when (status) {
@@ -12,7 +12,7 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.appcompat.widget.Toolbar import android.widget.Toolbar
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@@ -10,7 +10,6 @@ import android.widget.FrameLayout
import android.widget.ImageView import android.widget.ImageView
import android.widget.ProgressBar import android.widget.ProgressBar
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import coil.api.clear import coil.api.clear
import coil.api.load import coil.api.load
@@ -55,7 +54,7 @@ class ProductsAdapter(private val onClick: (ProductItem) -> Unit):
} }
} }
private class EmptyViewHolder(context: Context): RecyclerView.ViewHolder(AppCompatTextView(context)) { private class EmptyViewHolder(context: Context): RecyclerView.ViewHolder(TextView(context)) {
val text: TextView val text: TextView
get() = itemView as TextView get() = itemView as TextView
@@ -143,7 +142,7 @@ class ProductsAdapter(private val onClick: (ProductItem) -> Unit):
resources.sizeScaled(4).let { setPadding(it, 0, it, 0) } resources.sizeScaled(4).let { setPadding(it, 0, it, 0) }
setTextColor(holder.status.context.getColorFromAttr(android.R.attr.colorBackground)) setTextColor(holder.status.context.getColorFromAttr(android.R.attr.colorBackground))
background = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, null).apply { background = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, null).apply {
color = holder.status.context.getColorFromAttr(R.attr.colorAccent) color = holder.status.context.getColorFromAttr(android.R.attr.colorAccent)
cornerRadius = holder.status.resources.sizeScaled(2).toFloat() cornerRadius = holder.status.resources.sizeScaled(2).toFloat()
} }
} }
@@ -73,7 +73,7 @@ class ProductsFragment(): Fragment(), CursorOwner.Callback {
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return RecyclerView(container!!.context).apply { return RecyclerView(requireContext()).apply {
id = android.R.id.list id = android.R.id.list
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
isMotionEventSplittingEnabled = false isMotionEventSplittingEnabled = false
@@ -2,8 +2,8 @@ package nya.kitsunyan.foxydroid.screen
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Switch
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.widget.SwitchCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.R
import nya.kitsunyan.foxydroid.database.Database import nya.kitsunyan.foxydroid.database.Database
@@ -18,7 +18,7 @@ class RepositoriesAdapter(private val onClick: (Repository) -> Unit,
private class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { private class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val name = itemView.findViewById<TextView>(R.id.name)!! val name = itemView.findViewById<TextView>(R.id.name)!!
val enabled = itemView.findViewById<SwitchCompat>(R.id.enabled)!! val enabled = itemView.findViewById<Switch>(R.id.enabled)!!
var listenSwitch = true var listenSwitch = true
} }
@@ -7,7 +7,7 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.appcompat.widget.Toolbar import android.widget.Toolbar
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@@ -13,7 +13,7 @@ import android.widget.FrameLayout
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.ScrollView import android.widget.ScrollView
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.widget.Toolbar import android.widget.Toolbar
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
@@ -9,9 +9,9 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.appcompat.app.AppCompatActivity import android.widget.Toolbar
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.R
import nya.kitsunyan.foxydroid.content.Cache import nya.kitsunyan.foxydroid.content.Cache
import nya.kitsunyan.foxydroid.content.Preferences import nya.kitsunyan.foxydroid.content.Preferences
@@ -23,7 +23,7 @@ import nya.kitsunyan.foxydroid.utility.extension.resources.*
import nya.kitsunyan.foxydroid.utility.extension.text.* import nya.kitsunyan.foxydroid.utility.extension.text.*
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
abstract class ScreenActivity: AppCompatActivity() { abstract class ScreenActivity: FragmentActivity() {
companion object { companion object {
private const val STATE_FRAGMENT_STACK = "fragmentStack" private const val STATE_FRAGMENT_STACK = "fragmentStack"
} }
@@ -162,7 +162,7 @@ abstract class ScreenActivity: AppCompatActivity() {
internal fun onFragmentViewCreated(toolbar: Toolbar?) { internal fun onFragmentViewCreated(toolbar: Toolbar?) {
this.toolbar = toolbar?.let(::WeakReference) this.toolbar = toolbar?.let(::WeakReference)
if (fragmentStack.isNotEmpty() && toolbar != null) { if (fragmentStack.isNotEmpty() && toolbar != null) {
toolbar.navigationIcon = toolbar.context.getDrawableFromAttr(R.attr.homeAsUpIndicator) toolbar.navigationIcon = toolbar.context.getDrawableFromAttr(android.R.attr.homeAsUpIndicator)
toolbar.setNavigationOnClickListener { onBackPressed() } toolbar.setNavigationOnClickListener { onBackPressed() }
} }
} }
@@ -8,7 +8,6 @@ import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
@@ -75,7 +74,7 @@ class ScreenshotsFragment(): DialogFragment() {
format = PixelFormat.TRANSLUCENT format = PixelFormat.TRANSLUCENT
windowAnimations = run { windowAnimations = run {
val typedArray = dialog.context.obtainStyledAttributes(null, val typedArray = dialog.context.obtainStyledAttributes(null,
intArrayOf(android.R.attr.windowAnimationStyle), R.attr.dialogTheme, 0) intArrayOf(android.R.attr.windowAnimationStyle), android.R.attr.dialogTheme, 0)
try { try {
typedArray.getResourceId(0, 0) typedArray.getResourceId(0, 0)
} finally { } finally {
@@ -156,7 +155,7 @@ class ScreenshotsFragment(): DialogFragment() {
StableRecyclerAdapter<Adapter.ViewType, RecyclerView.ViewHolder>() { StableRecyclerAdapter<Adapter.ViewType, RecyclerView.ViewHolder>() {
enum class ViewType { SCREENSHOT } enum class ViewType { SCREENSHOT }
private class ViewHolder(context: Context): RecyclerView.ViewHolder(AppCompatImageView(context)) { private class ViewHolder(context: Context): RecyclerView.ViewHolder(ImageView(context)) {
val image: ImageView val image: ImageView
get() = itemView as ImageView get() = itemView as ImageView
@@ -2,6 +2,12 @@ package nya.kitsunyan.foxydroid.screen
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.content.Context import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Canvas
import android.graphics.ColorFilter
import android.graphics.Paint
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.Bundle
import android.view.Gravity import android.view.Gravity
import android.view.LayoutInflater import android.view.LayoutInflater
@@ -12,17 +18,15 @@ import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator import android.view.animation.DecelerateInterpolator
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.ImageView import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.SearchView
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.widget.AppCompatTextView import android.widget.Toolbar
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.Toolbar
import androidx.core.view.MenuCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayout import androidx.viewpager2.widget.ViewPager2
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.disposables.Disposable
@@ -34,6 +38,7 @@ import nya.kitsunyan.foxydroid.service.Connection
import nya.kitsunyan.foxydroid.service.SyncService import nya.kitsunyan.foxydroid.service.SyncService
import nya.kitsunyan.foxydroid.utility.RxUtils import nya.kitsunyan.foxydroid.utility.RxUtils
import nya.kitsunyan.foxydroid.utility.Utils import nya.kitsunyan.foxydroid.utility.Utils
import nya.kitsunyan.foxydroid.utility.extension.android.*
import nya.kitsunyan.foxydroid.utility.extension.resources.* import nya.kitsunyan.foxydroid.utility.extension.resources.*
import nya.kitsunyan.foxydroid.utility.extension.text.* import nya.kitsunyan.foxydroid.utility.extension.text.*
import nya.kitsunyan.foxydroid.widget.EnumRecyclerAdapter import nya.kitsunyan.foxydroid.widget.EnumRecyclerAdapter
@@ -49,7 +54,7 @@ class TabsFragment: Fragment() {
} }
private class Layout(view: View) { private class Layout(view: View) {
val tabLayout = view.findViewById<TabLayout>(R.id.tabs)!! val tabs = view.findViewById<LinearLayout>(R.id.tabs)!!
val categoryLayout = view.findViewById<ViewGroup>(R.id.category_layout)!! val categoryLayout = view.findViewById<ViewGroup>(R.id.category_layout)!!
val categoryChange = view.findViewById<View>(R.id.category_change)!! val categoryChange = view.findViewById<View>(R.id.category_change)!!
val categoryName = view.findViewById<TextView>(R.id.category_name)!! val categoryName = view.findViewById<TextView>(R.id.category_name)!!
@@ -57,17 +62,18 @@ class TabsFragment: Fragment() {
} }
private var sortOrderMenu: Pair<MenuItem, List<MenuItem>>? = null private var sortOrderMenu: Pair<MenuItem, List<MenuItem>>? = null
private var syncRepositoriesMenuItem: MenuItem? = null
private var layout: Layout? = null private var layout: Layout? = null
private var categoriesList: RecyclerView? = null private var categoriesList: RecyclerView? = null
private var viewPager: ViewPager? = null private var viewPager: ViewPager2? = null
private var showCategories = false private var showCategories = false
set(value) { set(value) {
if (field != value) { if (field != value) {
field = value field = value
val layout = layout val layout = layout
layout?.tabLayout?.let { (0 until it.tabCount) layout?.tabs?.let { (0 until it.childCount)
.forEach { index -> it.getTabAt(index)!!.view.isEnabled = !value } } .forEach { index -> it.getChildAt(index)!!.isEnabled = !value } }
layout?.categoryIcon?.scaleY = if (value) -1f else 1f layout?.categoryIcon?.scaleY = if (value) -1f else 1f
if ((categoriesList?.parent as? View)?.height ?: 0 > 0) { if ((categoriesList?.parent as? View)?.height ?: 0 > 0) {
animateCategoriesList() animateCategoriesList()
@@ -127,7 +133,9 @@ class TabsFragment: Fragment() {
}) })
toolbar.menu.apply { toolbar.menu.apply {
MenuCompat.setGroupDividerEnabled(this, true) if (Android.sdk(28)) {
setGroupDividerEnabled(true)
}
add(0, R.id.toolbar_search, 0, R.string.search) add(0, R.id.toolbar_search, 0, R.string.search)
.setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_search)) .setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_search))
@@ -138,21 +146,22 @@ class TabsFragment: Fragment() {
.setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_sort)) .setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_sort))
.let { menu -> .let { menu ->
menu.item.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS) menu.item.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS)
val items = ProductItem.Order.values().map { order -> menu val items = ProductItem.Order.values().map { order ->
.add(order.titleResId) menu
.setOnMenuItemClickListener { item -> .add(order.titleResId)
this@TabsFragment.order = order .setOnMenuItemClickListener { item ->
item.isChecked = true this@TabsFragment.order = order
productFragments.forEach { it.setOrder(order) } item.isChecked = true
true productFragments.forEach { it.setOrder(order) }
} } true
}
}
menu.setGroupCheckable(0, true, true) menu.setGroupCheckable(0, true, true)
Pair(menu.item, items) Pair(menu.item, items)
} }
add(0, 0, 0, R.string.sync_repositories) syncRepositoriesMenuItem = add(0, 0, 0, R.string.sync_repositories)
.setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_sync)) .setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_sync))
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM)
.setOnMenuItemClickListener { .setOnMenuItemClickListener {
syncConnection.binder?.sync(SyncService.SyncRequest.MANUAL) syncConnection.binder?.sync(SyncService.SyncRequest.MANUAL)
true true
@@ -179,16 +188,27 @@ class TabsFragment: Fragment() {
val layout = Layout(view) val layout = Layout(view)
this.layout = layout this.layout = layout
ProductsFragment.Source.values().forEach { layout.tabLayout layout.tabs.background = TabsBackgroundDrawable(layout.tabs.context,
.addTab(layout.tabLayout.newTab().setText(it.titleResId)) } layout.tabs.layoutDirection == View.LAYOUT_DIRECTION_RTL)
layout.tabLayout.addOnTabSelectedListener(object: TabLayout.OnTabSelectedListener { ProductsFragment.Source.values().forEach {
override fun onTabSelected(tab: TabLayout.Tab) { val tab = TextView(layout.tabs.context)
viewPager!!.currentItem = tab.position val selectedColor = tab.context.getColorFromAttr(android.R.attr.textColorPrimary).defaultColor
val normalColor = tab.context.getColorFromAttr(android.R.attr.textColorSecondary).defaultColor
tab.gravity = Gravity.CENTER
tab.typeface = TypefaceExtra.medium
tab.setTextColor(ColorStateList(arrayOf(intArrayOf(android.R.attr.state_selected), intArrayOf()),
intArrayOf(selectedColor, normalColor)))
tab.setTextSizeScaled(14)
tab.isAllCaps = true
tab.text = getString(it.titleResId)
tab.background = tab.context.getDrawableFromAttr(android.R.attr.selectableItemBackground)
tab.setOnClickListener { _ ->
setSelectedTab(it)
viewPager!!.currentItem = it.ordinal
} }
layout.tabs.addView(tab, 0, LinearLayout.LayoutParams.MATCH_PARENT)
override fun onTabUnselected(tab: TabLayout.Tab) = Unit (tab.layoutParams as LinearLayout.LayoutParams).weight = 1f
override fun onTabReselected(tab: TabLayout.Tab) = Unit }
})
showCategories = savedInstanceState?.getByte(STATE_SHOW_CATEGORIES)?.toInt() ?: 0 != 0 showCategories = savedInstanceState?.getByte(STATE_SHOW_CATEGORIES)?.toInt() ?: 0 != 0
categories = savedInstanceState?.getStringArrayList(STATE_CATEGORIES).orEmpty() categories = savedInstanceState?.getStringArrayList(STATE_CATEGORIES).orEmpty()
@@ -201,14 +221,16 @@ class TabsFragment: Fragment() {
val content = view.findViewById<FrameLayout>(R.id.fragment_content) val content = view.findViewById<FrameLayout>(R.id.fragment_content)
viewPager = ViewPager(content.context).apply { viewPager = ViewPager2(content.context).apply {
id = R.id.fragment_pager id = R.id.fragment_pager
adapter = object: FragmentStatePagerAdapter(childFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { adapter = object: FragmentStateAdapter(this@TabsFragment) {
override fun getItem(position: Int): Fragment = ProductsFragment(ProductsFragment.Source.values()[position]) override fun getItemCount(): Int = ProductsFragment.Source.values().size
override fun getCount(): Int = ProductsFragment.Source.values().size override fun createFragment(position: Int): Fragment = ProductsFragment(ProductsFragment
.Source.values()[position])
} }
content.addView(this, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) content.addView(this, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
addOnPageChangeListener(pageChangeListener) registerOnPageChangeCallback(pageChangeCallback)
offscreenPageLimit = 1
} }
categoriesDisposable = Observable.just(Unit) categoriesDisposable = Observable.just(Unit)
@@ -238,7 +260,7 @@ class TabsFragment: Fragment() {
updateCategory() updateCategory()
} }
} }
setBackgroundColor(context.getColorFromAttr(R.attr.colorPrimaryDark).defaultColor) setBackgroundColor(context.getColorFromAttr(android.R.attr.colorPrimaryDark).defaultColor)
elevation = resources.sizeScaled(4).toFloat() elevation = resources.sizeScaled(4).toFloat()
content.addView(this, FrameLayout.LayoutParams.MATCH_PARENT, 0) content.addView(this, FrameLayout.LayoutParams.MATCH_PARENT, 0)
visibility = View.GONE visibility = View.GONE
@@ -268,6 +290,7 @@ class TabsFragment: Fragment() {
super.onDestroyView() super.onDestroyView()
sortOrderMenu = null sortOrderMenu = null
syncRepositoriesMenuItem = null
layout = null layout = null
categoriesList = null categoriesList = null
viewPager = null viewPager = null
@@ -294,7 +317,7 @@ class TabsFragment: Fragment() {
if (needSelectUpdates) { if (needSelectUpdates) {
needSelectUpdates = false needSelectUpdates = false
selectUpdates() selectUpdatesInternal(false)
} }
} }
@@ -308,11 +331,19 @@ class TabsFragment: Fragment() {
} }
} }
internal fun selectUpdates() { private fun setSelectedTab(source: ProductsFragment.Source) {
if (view == null) { val layout = layout!!
needSelectUpdates = true (0 until layout.tabs.childCount).forEach { layout.tabs.getChildAt(it).isSelected = it == source.ordinal }
}
internal fun selectUpdates() = selectUpdatesInternal(true)
private fun selectUpdatesInternal(allowSmooth: Boolean) {
if (view != null) {
val viewPager = viewPager
viewPager?.setCurrentItem(ProductsFragment.Source.UPDATES.ordinal, allowSmooth && viewPager.isLaidOut)
} else { } else {
layout?.tabLayout?.getTabAt(ProductsFragment.Source.UPDATES.ordinal)!!.select() needSelectUpdates = true
} }
} }
@@ -369,7 +400,7 @@ class TabsFragment: Fragment() {
} }
} }
private val pageChangeListener = object: ViewPager.OnPageChangeListener { private val pageChangeCallback = object: ViewPager2.OnPageChangeCallback() {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
val layout = layout!! val layout = layout!!
val fromCategories = ProductsFragment.Source.values()[position].categories val fromCategories = ProductsFragment.Source.values()[position].categories
@@ -380,14 +411,12 @@ class TabsFragment: Fragment() {
} else { } else {
if (fromCategories) 1f else 0f if (fromCategories) 1f else 0f
} }
if (layout.categoryLayout.childCount != 1) { (layout.tabs.background as TabsBackgroundDrawable)
throw RuntimeException() .update(position + positionOffset, layout.tabs.childCount)
} assert(layout.categoryLayout.childCount == 1)
val child = layout.categoryLayout.getChildAt(0) val child = layout.categoryLayout.getChildAt(0)
val height = child.layoutParams.height val height = child.layoutParams.height
if (height <= 0) { assert(height > 0)
throw RuntimeException()
}
val currentHeight = (offset * height).roundToInt() val currentHeight = (offset * height).roundToInt()
if (layout.categoryLayout.layoutParams.height != currentHeight) { if (layout.categoryLayout.layoutParams.height != currentHeight) {
layout.categoryLayout.layoutParams.height = currentHeight layout.categoryLayout.layoutParams.height = currentHeight
@@ -396,27 +425,63 @@ class TabsFragment: Fragment() {
} }
override fun onPageSelected(position: Int) { override fun onPageSelected(position: Int) {
val layout = layout!!
val source = ProductsFragment.Source.values()[position] val source = ProductsFragment.Source.values()[position]
updateUpdateNotificationBlocker(source) updateUpdateNotificationBlocker(source)
sortOrderMenu!!.first.isVisible = source.order sortOrderMenu!!.first.isVisible = source.order
layout.tabLayout.selectTab(layout.tabLayout.getTabAt(source.ordinal)) syncRepositoriesMenuItem!!.setShowAsActionFlags(if (!source.order ||
resources.configuration.screenWidthDp >= 480) MenuItem.SHOW_AS_ACTION_ALWAYS else 0)
setSelectedTab(source)
if (showCategories && !source.categories) { if (showCategories && !source.categories) {
showCategories = false showCategories = false
} }
} }
override fun onPageScrollStateChanged(state: Int) { override fun onPageScrollStateChanged(state: Int) {
layout!!.categoryChange.isEnabled = state != ViewPager.SCROLL_STATE_DRAGGING && layout!!.categoryChange.isEnabled = state != ViewPager2.SCROLL_STATE_DRAGGING &&
ProductsFragment.Source.values()[viewPager!!.currentItem].categories ProductsFragment.Source.values()[viewPager!!.currentItem].categories
} }
} }
private class TabsBackgroundDrawable(context: Context, private val rtl: Boolean): Drawable() {
private val height = context.resources.sizeScaled(2)
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = context.getColorFromAttr(android.R.attr.colorAccent).defaultColor
}
private var position = 0f
private var total = 0
fun update(position: Float, total: Int) {
this.position = position
this.total = total
invalidateSelf()
}
override fun draw(canvas: Canvas) {
if (total > 0) {
val bounds = bounds
val width = bounds.width() / total.toFloat()
val x = width * position
if (rtl) {
canvas.drawRect(bounds.right - width - x, (bounds.bottom - height).toFloat(),
bounds.right - x, bounds.bottom.toFloat(), paint)
} else {
canvas.drawRect(bounds.left + x, (bounds.bottom - height).toFloat(),
bounds.left + x + width, bounds.bottom.toFloat(), paint)
}
}
}
override fun setAlpha(alpha: Int) = Unit
override fun setColorFilter(colorFilter: ColorFilter?) = Unit
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
}
private class CategoriesAdapter(private val categories: () -> List<String>, private val onClick: (String) -> Unit): private class CategoriesAdapter(private val categories: () -> List<String>, private val onClick: (String) -> Unit):
EnumRecyclerAdapter<CategoriesAdapter.ViewType, RecyclerView.ViewHolder>() { EnumRecyclerAdapter<CategoriesAdapter.ViewType, RecyclerView.ViewHolder>() {
enum class ViewType { CATEGORY } enum class ViewType { CATEGORY }
private class CategoryViewHolder(context: Context): RecyclerView.ViewHolder(AppCompatTextView(context)) { private class CategoryViewHolder(context: Context): RecyclerView.ViewHolder(TextView(context)) {
val title: TextView val title: TextView
get() = itemView as TextView get() = itemView as TextView
@@ -426,7 +491,7 @@ class TabsFragment: Fragment() {
itemView.resources.sizeScaled(16).let { itemView.setPadding(it, 0, it, 0) } itemView.resources.sizeScaled(16).let { itemView.setPadding(it, 0, it, 0) }
itemView.setTextColor(context.getColorFromAttr(android.R.attr.textColorPrimary)) itemView.setTextColor(context.getColorFromAttr(android.R.attr.textColorPrimary))
itemView.setTextSizeScaled(16) itemView.setTextSizeScaled(16)
itemView.background = context.getDrawableFromAttr(R.attr.selectableItemBackground) itemView.background = context.getDrawableFromAttr(android.R.attr.selectableItemBackground)
itemView.layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, itemView.layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT,
itemView.resources.sizeScaled(48)) itemView.resources.sizeScaled(48))
} }
@@ -3,7 +3,7 @@ package nya.kitsunyan.foxydroid.service
import android.app.Service import android.app.Service
import android.content.Intent import android.content.Intent
import android.os.IBinder import android.os.IBinder
import nya.kitsunyan.foxydroid.utility.extension.android.Android import nya.kitsunyan.foxydroid.utility.extension.android.*
abstract class ConnectionService<T: IBinder>: Service() { abstract class ConnectionService<T: IBinder>: Service() {
abstract override fun onBind(intent: Intent): T abstract override fun onBind(intent: Intent): T
@@ -7,7 +7,7 @@ import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import androidx.appcompat.view.ContextThemeWrapper import android.view.ContextThemeWrapper
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
@@ -188,7 +188,7 @@ class DownloadService: ConnectionService<DownloadService.Binder>() {
.setAutoCancel(true) .setAutoCancel(true)
.setSmallIcon(android.R.drawable.stat_sys_warning) .setSmallIcon(android.R.drawable.stat_sys_warning)
.setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light) .setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light)
.getColorFromAttr(R.attr.colorAccent).defaultColor) .getColorFromAttr(android.R.attr.colorAccent).defaultColor)
.setContentIntent(PendingIntent.getBroadcast(this, 0, Intent(this, Receiver::class.java) .setContentIntent(PendingIntent.getBroadcast(this, 0, Intent(this, Receiver::class.java)
.setAction("$ACTION_OPEN.${task.packageName}"), PendingIntent.FLAG_UPDATE_CURRENT)) .setAction("$ACTION_OPEN.${task.packageName}"), PendingIntent.FLAG_UPDATE_CURRENT))
.apply { .apply {
@@ -223,7 +223,7 @@ class DownloadService: ConnectionService<DownloadService.Binder>() {
.setAutoCancel(true) .setAutoCancel(true)
.setSmallIcon(android.R.drawable.stat_sys_download_done) .setSmallIcon(android.R.drawable.stat_sys_download_done)
.setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light) .setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light)
.getColorFromAttr(R.attr.colorAccent).defaultColor) .getColorFromAttr(android.R.attr.colorAccent).defaultColor)
.setContentIntent(PendingIntent.getBroadcast(this, 0, Intent(this, Receiver::class.java) .setContentIntent(PendingIntent.getBroadcast(this, 0, Intent(this, Receiver::class.java)
.setAction("$ACTION_INSTALL.${task.packageName}") .setAction("$ACTION_INSTALL.${task.packageName}")
.putExtra(EXTRA_CACHE_FILE_NAME, task.release.cacheFileName), PendingIntent.FLAG_UPDATE_CURRENT)) .putExtra(EXTRA_CACHE_FILE_NAME, task.release.cacheFileName), PendingIntent.FLAG_UPDATE_CURRENT))
@@ -286,7 +286,7 @@ class DownloadService: ConnectionService<DownloadService.Binder>() {
.Builder(this, Common.NOTIFICATION_CHANNEL_DOWNLOADING) .Builder(this, Common.NOTIFICATION_CHANNEL_DOWNLOADING)
.setSmallIcon(android.R.drawable.stat_sys_download) .setSmallIcon(android.R.drawable.stat_sys_download)
.setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light) .setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light)
.getColorFromAttr(R.attr.colorAccent).defaultColor) .getColorFromAttr(android.R.attr.colorAccent).defaultColor)
.addAction(0, getString(R.string.cancel), PendingIntent.getService(this, 0, .addAction(0, getString(R.string.cancel), PendingIntent.getService(this, 0,
Intent(this, this::class.java).setAction(ACTION_CANCEL), PendingIntent.FLAG_UPDATE_CURRENT)) } Intent(this, this::class.java).setAction(ACTION_CANCEL), PendingIntent.FLAG_UPDATE_CURRENT)) }
@@ -9,7 +9,7 @@ import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import androidx.appcompat.view.ContextThemeWrapper import android.view.ContextThemeWrapper
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
@@ -200,7 +200,7 @@ class SyncService: ConnectionService<SyncService.Binder>() {
.Builder(this, Common.NOTIFICATION_CHANNEL_SYNCING) .Builder(this, Common.NOTIFICATION_CHANNEL_SYNCING)
.setSmallIcon(android.R.drawable.stat_sys_warning) .setSmallIcon(android.R.drawable.stat_sys_warning)
.setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light) .setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light)
.getColorFromAttr(R.attr.colorAccent).defaultColor) .getColorFromAttr(android.R.attr.colorAccent).defaultColor)
.setContentTitle(getString(R.string.error_syncing_format, repository.name)) .setContentTitle(getString(R.string.error_syncing_format, repository.name))
.setContentText(getString(when (exception) { .setContentText(getString(when (exception) {
is RepositoryUpdater.UpdateException -> when (exception.errorType) { is RepositoryUpdater.UpdateException -> when (exception.errorType) {
@@ -218,7 +218,7 @@ class SyncService: ConnectionService<SyncService.Binder>() {
.Builder(this, Common.NOTIFICATION_CHANNEL_SYNCING) .Builder(this, Common.NOTIFICATION_CHANNEL_SYNCING)
.setSmallIcon(R.drawable.ic_sync) .setSmallIcon(R.drawable.ic_sync)
.setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light) .setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light)
.getColorFromAttr(R.attr.colorAccent).defaultColor) .getColorFromAttr(android.R.attr.colorAccent).defaultColor)
.addAction(0, getString(R.string.cancel), PendingIntent.getService(this, 0, .addAction(0, getString(R.string.cancel), PendingIntent.getService(this, 0,
Intent(this, this::class.java).setAction(ACTION_CANCEL), PendingIntent.FLAG_UPDATE_CURRENT)) } Intent(this, this::class.java).setAction(ACTION_CANCEL), PendingIntent.FLAG_UPDATE_CURRENT)) }
@@ -353,7 +353,7 @@ class SyncService: ConnectionService<SyncService.Binder>() {
.setContentText(resources.getQuantityString(R.plurals.new_updates_description_format, .setContentText(resources.getQuantityString(R.plurals.new_updates_description_format,
productItems.size, productItems.size)) productItems.size, productItems.size))
.setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light) .setColor(ContextThemeWrapper(this, R.style.Theme_Main_Light)
.getColorFromAttr(R.attr.colorAccent).defaultColor) .getColorFromAttr(android.R.attr.colorAccent).defaultColor)
.setContentIntent(PendingIntent.getActivity(this, 0, Intent(this, MainActivity::class.java) .setContentIntent(PendingIntent.getActivity(this, 0, Intent(this, MainActivity::class.java)
.setAction(MainActivity.ACTION_UPDATES), PendingIntent.FLAG_UPDATE_CURRENT)) .setAction(MainActivity.ACTION_UPDATES), PendingIntent.FLAG_UPDATE_CURRENT))
.setStyle(NotificationCompat.InboxStyle().applyHack { .setStyle(NotificationCompat.InboxStyle().applyHack {
@@ -24,7 +24,7 @@ object Utils {
fun getDefaultApplicationIcons(context: Context): Pair<Drawable, Drawable> { fun getDefaultApplicationIcons(context: Context): Pair<Drawable, Drawable> {
val progressIcon: Drawable = createDefaultApplicationIcon(context, android.R.attr.textColorSecondary) val progressIcon: Drawable = createDefaultApplicationIcon(context, android.R.attr.textColorSecondary)
val defaultIcon: Drawable = createDefaultApplicationIcon(context, R.attr.colorAccent) val defaultIcon: Drawable = createDefaultApplicationIcon(context, android.R.attr.colorAccent)
return Pair(progressIcon, defaultIcon) return Pair(progressIcon, defaultIcon)
} }
@@ -5,6 +5,7 @@ import android.graphics.Canvas
import android.graphics.Rect import android.graphics.Rect
import android.os.SystemClock import android.os.SystemClock
import android.view.MotionEvent import android.view.MotionEvent
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import nya.kitsunyan.foxydroid.utility.extension.resources.* import nya.kitsunyan.foxydroid.utility.extension.resources.*
@@ -23,7 +24,7 @@ class RecyclerFastScroller(private val recyclerView: RecyclerView) {
private val thumbDrawable = recyclerView.context.getDrawableFromAttr(android.R.attr.fastScrollThumbDrawable) private val thumbDrawable = recyclerView.context.getDrawableFromAttr(android.R.attr.fastScrollThumbDrawable)
private val trackDrawable = recyclerView.context.getDrawableFromAttr(android.R.attr.fastScrollTrackDrawable) private val trackDrawable = recyclerView.context.getDrawableFromAttr(android.R.attr.fastScrollTrackDrawable)
private val minTrackSize = recyclerView.resources.sizeScaled(32) private val minTrackSize = recyclerView.resources.sizeScaled(16)
private data class FastScrolling(val startAtThumbOffset: Float?, val startY: Float, val currentY: Float) private data class FastScrolling(val startAtThumbOffset: Float?, val startY: Float, val currentY: Float)
@@ -134,6 +135,7 @@ class RecyclerFastScroller(private val recyclerView: RecyclerView) {
val atThumbVertical = if (rtl) event.x <= trackWidth else event.x >= recyclerView.width - trackWidth val atThumbVertical = if (rtl) event.x <= trackWidth else event.x >= recyclerView.width - trackWidth
atThumbVertical && run { atThumbVertical && run {
withScroll { itemHeight, thumbHeight, range -> withScroll { itemHeight, thumbHeight, range ->
(recyclerView.parent as? ViewGroup)?.requestDisallowInterceptTouchEvent(true)
val offset = currentOffset(itemHeight, range) val offset = currentOffset(itemHeight, range)
val thumbY = ((recyclerView.height - thumbHeight) * offset).roundToInt() val thumbY = ((recyclerView.height - thumbHeight) * offset).roundToInt()
val atThumb = event.y >= thumbY && event.y <= thumbY + thumbHeight val atThumb = event.y >= thumbY && event.y <= thumbY + thumbHeight
@@ -153,6 +155,7 @@ class RecyclerFastScroller(private val recyclerView: RecyclerView) {
} }
val cancel = event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL val cancel = event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL
if (!success || cancel) { if (!success || cancel) {
(recyclerView.parent as? ViewGroup)?.requestDisallowInterceptTouchEvent(false)
updateState(scrolling, null) updateState(scrolling, null)
recyclerView.invalidate() recyclerView.invalidate()
} }
@@ -0,0 +1,33 @@
package nya.kitsunyan.foxydroid.widget
import android.content.Context
import android.util.AttributeSet
import android.widget.Toolbar
class Toolbar: Toolbar {
constructor(context: Context): super(context)
constructor(context: Context, attrs: AttributeSet?): super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int,
defStyleRes: Int): super(context, attrs, defStyleAttr, defStyleRes)
private var initalized = false
private var layoutDirectionChanged: Int? = null
init {
initalized = true
val layoutDirection = layoutDirectionChanged
layoutDirectionChanged = null
if (layoutDirection != null) {
onRtlPropertiesChanged(layoutDirection)
}
}
override fun onRtlPropertiesChanged(layoutDirection: Int) {
if (initalized) {
super.onRtlPropertiesChanged(layoutDirection)
} else {
layoutDirectionChanged = layoutDirection
}
}
}
+4 -3
View File
@@ -55,7 +55,8 @@
android:scaleType="center" android:scaleType="center"
android:src="@drawable/ic_arrow_down" android:src="@drawable/ic_arrow_down"
android:tint="?android:attr/textColorSecondary" android:tint="?android:attr/textColorSecondary"
android:background="?attr/actionBarItemBackground" android:tintMode="src_in"
android:background="?android:attr/actionBarItemBackground"
android:visibility="gone" android:visibility="gone"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
@@ -91,7 +92,7 @@
android:paddingTop="16dp" android:paddingTop="16dp"
android:paddingBottom="16dp" android:paddingBottom="16dp"
android:gravity="top" android:gravity="top"
android:typeface="monospace" android:fontFamily="monospace"
android:textSize="16sp" android:textSize="16sp"
android:inputType="textNoSuggestions|textMultiLine" android:inputType="textNoSuggestions|textMultiLine"
tools:ignore="Autofill,LabelFor" /> tools:ignore="Autofill,LabelFor" />
@@ -208,7 +209,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
style="@style/Widget.AppCompat.Button.Borderless.Colored" style="@android:style/Widget.Material.Button.Borderless.Colored"
android:text="@string/skip" /> android:text="@string/skip" />
</LinearLayout> </LinearLayout>
+8 -6
View File
@@ -1,28 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<nya.kitsunyan.foxydroid.widget.FragmentLinearLayout <nya.kitsunyan.foxydroid.widget.FragmentLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme"> android:orientation="vertical"
android:theme="?android:attr/actionBarTheme"
android:background="?android:attr/colorPrimary"
android:elevation="4dp">
<androidx.appcompat.widget.Toolbar <nya.kitsunyan.foxydroid.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:popupTheme="@style/Theme.Toolbar.Popup" /> android:popupTheme="@style/Theme.Toolbar.Popup" />
<FrameLayout <FrameLayout
android:id="@+id/toolbar_extra" android:id="@+id/toolbar_extra"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</com.google.android.material.appbar.AppBarLayout> </LinearLayout>
<FrameLayout <FrameLayout
android:id="@+id/fragment_content" android:id="@+id/fragment_content"
+2 -1
View File
@@ -7,7 +7,7 @@
android:orientation="horizontal" android:orientation="horizontal"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground"> android:background="?android:attr/selectableItemBackground">
<ImageView <ImageView
android:id="@+id/icon" android:id="@+id/icon"
@@ -15,6 +15,7 @@
android:layout_height="24dp" android:layout_height="24dp"
android:scaleType="centerInside" android:scaleType="centerInside"
android:tint="?android:attr/textColorSecondary" android:tint="?android:attr/textColorSecondary"
android:tintMode="src_in"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
<LinearLayout <LinearLayout
+1 -1
View File
@@ -7,7 +7,7 @@
android:orientation="horizontal" android:orientation="horizontal"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground"> android:background="?android:attr/selectableItemBackground">
<ImageView <ImageView
android:id="@+id/icon" android:id="@+id/icon"
+42
View File
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="?android:attr/selectableItemBackground">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
android:singleLine="true" />
<TextView
android:id="@+id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp" />
</LinearLayout>
<Switch
android:id="@+id/check"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="-16dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:visibility="gone" />
</LinearLayout>
+2 -2
View File
@@ -66,7 +66,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_gravity="bottom" android:layout_gravity="bottom"
style="@style/Widget.AppCompat.Button.Colored" /> style="@android:style/Widget.Material.Button" />
</LinearLayout> </LinearLayout>
@@ -94,7 +94,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_marginBottom="2dp" android:layout_marginBottom="2dp"
style="@style/Widget.AppCompat.ProgressBar.Horizontal" /> style="@android:style/Widget.Material.ProgressBar.Horizontal" />
</LinearLayout> </LinearLayout>
+1 -1
View File
@@ -8,7 +8,7 @@
android:paddingStart="14dp" android:paddingStart="14dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:background="?attr/selectableItemBackground"> android:background="?android:attr/selectableItemBackground">
<ImageView <ImageView
android:id="@+id/icon" android:id="@+id/icon"
+1 -1
View File
@@ -8,7 +8,7 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:baselineAligned="false" android:baselineAligned="false"
android:padding="16dp" android:padding="16dp"
android:background="?attr/selectableItemBackground"> android:background="?android:attr/selectableItemBackground">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
+2 -2
View File
@@ -5,7 +5,7 @@
android:layout_height="54dp" android:layout_height="54dp"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical" android:gravity="center_vertical"
android:background="?attr/selectableItemBackground"> android:background="?android:attr/selectableItemBackground">
<TextView <TextView
android:id="@+id/name" android:id="@+id/name"
@@ -17,7 +17,7 @@
android:textSize="16sp" android:textSize="16sp"
android:singleLine="true" /> android:singleLine="true" />
<androidx.appcompat.widget.SwitchCompat <Switch
android:id="@+id/enabled" android:id="@+id/enabled"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
+2 -1
View File
@@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="16dp" android:padding="16dp"
android:background="?attr/selectableItemBackground"> android:background="?android:attr/selectableItemBackground">
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
@@ -25,6 +25,7 @@
android:scaleType="center" android:scaleType="center"
android:src="@drawable/ic_arrow_down" android:src="@drawable/ic_arrow_down"
android:tint="?android:attr/textColorPrimary" android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
</LinearLayout> </LinearLayout>
+2 -2
View File
@@ -5,7 +5,7 @@
android:layout_height="48dp" android:layout_height="48dp"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical" android:gravity="center_vertical"
android:background="?attr/selectableItemBackground"> android:background="?android:attr/selectableItemBackground">
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
@@ -17,7 +17,7 @@
android:textSize="16sp" android:textSize="16sp"
android:singleLine="true" /> android:singleLine="true" />
<androidx.appcompat.widget.SwitchCompat <Switch
android:id="@+id/enabled" android:id="@+id/enabled"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
+4 -6
View File
@@ -1,18 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.tabs.TabLayout <LinearLayout
android:id="@+id/tabs" android:id="@+id/tabs"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="48dp"
app:tabGravity="fill" android:orientation="horizontal" />
app:tabMaxWidth="0dp" />
<FrameLayout <FrameLayout
android:id="@+id/category_layout" android:id="@+id/category_layout"
@@ -27,7 +25,7 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingStart="12dp" android:paddingStart="12dp"
android:paddingEnd="12dp" android:paddingEnd="12dp"
android:background="?attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
tools:ignore="UselessParent"> tools:ignore="UselessParent">
<TextView <TextView
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="colorError" format="color" />
</resources>
+1
View File
@@ -5,6 +5,7 @@
<item type="id" name="divider_configuration" /> <item type="id" name="divider_configuration" />
<item type="id" name="fragment_pager" /> <item type="id" name="fragment_pager" />
<item type="id" name="main_content" /> <item type="id" name="main_content" />
<item type="id" name="preferences_list" />
<item type="id" name="toolbar_search" /> <item type="id" name="toolbar_search" />
</resources> </resources>
+15 -15
View File
@@ -1,30 +1,30 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<resources> <resources>
<style name="Theme.Main.Light" parent="Theme.AppCompat.Light.DarkActionBar"> <style name="Theme.Main.Light" parent="@android:style/Theme.Material.Light.DarkActionBar">
<item name="windowActionBar">false</item> <item name="android:windowActionBar">false</item>
<item name="windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
<item name="android:colorBackground">#fffafafa</item> <item name="android:colorBackground">#fffafafa</item>
<item name="colorPrimary">@color/primary_light</item> <item name="android:colorPrimary">@color/primary_light</item>
<item name="colorPrimaryDark">@color/primary_dark_light</item> <item name="android:colorPrimaryDark">@color/primary_dark_light</item>
<item name="colorAccent">@color/accent_light</item> <item name="android:colorAccent">@color/accent_light</item>
<item name="colorControlActivated">@color/accent_default_light</item> <item name="android:colorControlActivated">@color/accent_default_light</item>
<item name="colorError">@color/error_light</item> <item name="colorError">@color/error_light</item>
</style> </style>
<style name="Theme.Main.Dark" parent="Theme.AppCompat"> <style name="Theme.Main.Dark" parent="@android:style/Theme.Material">
<item name="windowActionBar">false</item> <item name="android:windowActionBar">false</item>
<item name="windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
<item name="android:colorBackground">#ff111111</item> <item name="android:colorBackground">#ff111111</item>
<item name="colorPrimary">@color/primary_dark</item> <item name="android:colorPrimary">@color/primary_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_dark</item> <item name="android:colorPrimaryDark">@color/primary_dark_dark</item>
<item name="colorAccent">@color/accent_dark</item> <item name="android:colorAccent">@color/accent_dark</item>
<item name="colorControlActivated">@color/accent_default_dark</item> <item name="android:colorControlActivated">@color/accent_default_dark</item>
<item name="colorError">@color/error_dark</item> <item name="colorError">@color/error_dark</item>
</style> </style>
<style name="Theme.Toolbar.Popup" parent="Theme.Main.Dark"> <style name="Theme.Toolbar.Popup" parent="Theme.Main.Dark">
<item name="android:colorBackground">?attr/colorPrimaryDark</item> <item name="android:colorBackground">?android:attr/colorPrimaryDark</item>
</style> </style>
</resources> </resources>