Skip to content

Commit

Permalink
Update Contribution filter activity design (#3619)
Browse files Browse the repository at this point in the history
* Update Contribution filter activity design

* Fix lint

* Add qq string

* Add a couple of rename

* Add logic of selecting items

* Add header view

* Corrected icon display

* Completed filter activity logic

* Bind filter activity with current filter icon

* Return empty list if no result

* Update visibility for empty container if no filter is selected

* Rename filter activity title text and string name

* Update filter setting to excluded one

* Update icon colors and text

* Update icon color to gray

* Replace check button with radio button

Co-authored-by: Sharvani Haran <sharvaniharan@users.noreply.github.com>
Co-authored-by: Dmitry Brant <dbrant@wikimedia.org>
  • Loading branch information
3 people committed Oct 26, 2022
1 parent c601428 commit 7731d86
Show file tree
Hide file tree
Showing 30 changed files with 337 additions and 653 deletions.
4 changes: 2 additions & 2 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -313,8 +313,8 @@
android:theme="@style/AppTheme" />

<activity
android:name=".usercontrib.UserContribWikiSelectActivity"
android:label="@string/user_contrib_wiki_select"
android:name=".usercontrib.UserContribFilterActivity"
android:label="@string/user_contrib_filter_activity_title"
android:theme="@style/AppTheme.ActionBar" />

<activity
Expand Down
Expand Up @@ -60,11 +60,6 @@ class NotificationFilterItemView constructor(context: Context, attrs: AttributeS
filter.imageRes?.let {
ImageViewCompat.setImageTintList(binding.notificationFilterWikiLogo,
ResourceUtil.getThemedColorStateList(context, R.attr.secondary_text_color))
if (NotificationCategory.isFiltersGroup(filter.filterCode)) {
val colorStateList = AppCompatResources.getColorStateList(context,
ResourceUtil.getThemedAttributeId(context, NotificationCategory.find(filter.filterCode).iconColor))
ImageViewCompat.setImageTintList(binding.notificationFilterWikiLogo, colorStateList)
}
binding.notificationFilterWikiLogo.setImageResource(it)
binding.notificationFilterWikiLogo.visibility = View.VISIBLE
} ?: run {
Expand Down
11 changes: 8 additions & 3 deletions app/src/main/java/org/wikipedia/settings/Prefs.kt
Expand Up @@ -5,6 +5,7 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.logging.HttpLoggingInterceptor
import org.wikipedia.BuildConfig
import org.wikipedia.R
import org.wikipedia.WikipediaApp
import org.wikipedia.analytics.SessionData
import org.wikipedia.analytics.SessionFunnel
import org.wikipedia.analytics.eventplatform.StreamConfig
Expand Down Expand Up @@ -602,10 +603,14 @@ object Prefs {
get() = PrefsIoUtil.getBoolean(R.string.preference_key_talk_topic_expand_all, true)
set(value) = PrefsIoUtil.setBoolean(R.string.preference_key_talk_topic_expand_all, value)

var userContribFilterNs
get() = JsonUtil.decodeFromString<Set<Int>>(PrefsIoUtil.getString(R.string.preference_key_user_contrib_filter_ns, null))
var userContribFilterExcludedNs
get() = JsonUtil.decodeFromString<Set<Int>>(PrefsIoUtil.getString(R.string.preference_key_user_contrib_filter_excluded_ns, null))
?: emptySet()
set(value) = PrefsIoUtil.setString(R.string.preference_key_user_contrib_filter_ns, JsonUtil.encodeToString(value))
set(value) = PrefsIoUtil.setString(R.string.preference_key_user_contrib_filter_excluded_ns, JsonUtil.encodeToString(value))

var userContribFilterLangCode
get() = PrefsIoUtil.getString(R.string.preference_key_user_contrib_filter_lang_code, WikipediaApp.instance.appOrSystemLanguageCode)!!
set(value) = PrefsIoUtil.setString(R.string.preference_key_user_contrib_filter_lang_code, value)

var editSyntaxHighlightEnabled
get() = PrefsIoUtil.getBoolean(R.string.preference_key_edit_syntax_highlight, true)
Expand Down
@@ -0,0 +1,187 @@
package org.wikipedia.usercontrib

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import org.wikipedia.Constants
import org.wikipedia.R
import org.wikipedia.WikipediaApp
import org.wikipedia.activity.BaseActivity
import org.wikipedia.databinding.ActivityUserContribWikiSelectBinding
import org.wikipedia.page.Namespace
import org.wikipedia.settings.Prefs
import org.wikipedia.settings.languages.WikipediaLanguagesActivity
import org.wikipedia.staticdata.TalkAliasData
import org.wikipedia.staticdata.UserAliasData
import org.wikipedia.staticdata.UserTalkAliasData
import org.wikipedia.views.DefaultViewHolder

class UserContribFilterActivity : BaseActivity() {

private lateinit var binding: ActivityUserContribWikiSelectBinding

private val langUpdateLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
binding.recyclerView.adapter = ItemAdapter(this)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityUserContribWikiSelectBinding.inflate(layoutInflater)

binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = ItemAdapter(this)
binding.recyclerView.itemAnimator = null
setContentView(binding.root)
setResult(RESULT_OK)
}

inner class ItemViewHolder constructor(itemView: UserContribFilterItemView) :
DefaultViewHolder<UserContribFilterItemView>(itemView) {
fun bindItem(item: Item) {
view.setContents(item)
}
}

private inner class FilterHeaderViewHolder constructor(itemView: View) :
DefaultViewHolder<View>(itemView) {
val headerText = itemView.findViewById<TextView>(R.id.filter_header_title)!!

fun bindItem(filterHeader: String) {
headerText.text = filterHeader
}
}

private inner class AddLanguageViewHolder constructor(itemView: UserContribFilterItemView) :
DefaultViewHolder<UserContribFilterItemView>(itemView), UserContribFilterItemView.Callback {
fun bindItem(text: String) {
(itemView as UserContribFilterItemView).callback = this
itemView.setSingleLabel(text)
}

override fun onSelected(item: Item?) {
langUpdateLauncher.launch(WikipediaLanguagesActivity.newIntent(this@UserContribFilterActivity, Constants.InvokeSource.USER_CONTRIB_ACTIVITY))
}
}

private inner class ItemAdapter(val context: Context) : RecyclerView.Adapter<DefaultViewHolder<*>>(), UserContribFilterItemView.Callback {
private val itemList = mutableListOf<Any>()

init {
itemList.add(getString(R.string.notifications_wiki_filter_header))
WikipediaApp.instance.languageState.appLanguageCodes.forEach { itemList.add(Item(FILTER_TYPE_WIKI, it, null)) }
itemList.add(Item(FILTER_TYPE_WIKI, Constants.WIKI_CODE_COMMONS, R.drawable.ic_commons_logo))
itemList.add(Item(FILTER_TYPE_WIKI, Constants.WIKI_CODE_WIKIDATA, R.drawable.ic_wikidata_logo))
itemList.add(getString(R.string.notifications_filter_update_app_languages))
itemList.add(getString(R.string.user_contrib_filter_ns_header))
itemList.add(Item(FILTER_TYPE_NAMESPACE, getString(R.string.user_contrib_filter_all), null))
itemList.add(Item(FILTER_TYPE_NAMESPACE, getString(R.string.namespace_article), R.drawable.ic_article_ltr_ooui))
itemList.add(Item(FILTER_TYPE_NAMESPACE, TalkAliasData.valueFor(WikipediaApp.instance.appOrSystemLanguageCode), R.drawable.ic_notification_article_talk))
itemList.add(Item(FILTER_TYPE_NAMESPACE, UserAliasData.valueFor(WikipediaApp.instance.appOrSystemLanguageCode), R.drawable.ic_user_avatar))
itemList.add(Item(FILTER_TYPE_NAMESPACE, UserTalkAliasData.valueFor(WikipediaApp.instance.appOrSystemLanguageCode), R.drawable.ic_notification_user_talk))
}

override fun onCreateViewHolder(parent: ViewGroup, type: Int): DefaultViewHolder<*> {
return when (type) {
VIEW_TYPE_HEADER -> {
FilterHeaderViewHolder(layoutInflater.inflate(R.layout.view_notification_filter_header, parent, false))
}
VIEW_TYPE_ADD_LANGUAGE -> {
AddLanguageViewHolder(UserContribFilterItemView(context))
}
else -> {
val view = UserContribFilterItemView(context)
view.callback = this
ItemViewHolder(view)
}
}
}

override fun getItemCount(): Int {
return itemList.size
}

override fun getItemViewType(position: Int): Int {
return if (itemList[position] is String && itemList[position] == getString(R.string.notifications_filter_update_app_languages)) VIEW_TYPE_ADD_LANGUAGE
else if (itemList[position] is String) VIEW_TYPE_HEADER
else VIEW_TYPE_ITEM
}

override fun onBindViewHolder(holder: DefaultViewHolder<*>, position: Int) {
when (holder) {
is FilterHeaderViewHolder -> holder.bindItem(itemList[position] as String)
is AddLanguageViewHolder -> holder.bindItem(itemList[position] as String)
else -> (holder as ItemViewHolder).bindItem(itemList[position] as Item)
}
}

override fun onSelected(item: Item?) {
item?.let {
if (it.type == FILTER_TYPE_WIKI) {
Prefs.userContribFilterLangCode = item.filterCode
} else if (it.type == FILTER_TYPE_NAMESPACE) {
var excludedNsFilter = Prefs.userContribFilterExcludedNs
when (val namespaceCode = getNamespaceCode(item.filterCode)) {
-1 -> { // Select "all"
excludedNsFilter = if (excludedNsFilter.isEmpty() || excludedNsFilter.size < NAMESPACE_LIST.size) {
NAMESPACE_LIST.toSet()
} else {
emptySet()
}
}
else -> {
excludedNsFilter = if (excludedNsFilter.contains(namespaceCode)) {
excludedNsFilter.minus(namespaceCode)
} else {
excludedNsFilter.plus(namespaceCode)
}
}
}
Prefs.userContribFilterExcludedNs = excludedNsFilter
}
}
notifyItemRangeChanged(0, itemCount)
}
}

private fun getNamespaceCode(text: String): Int {
return when (text) {
getString(R.string.namespace_article) -> Namespace.MAIN.code()
TalkAliasData.valueFor(WikipediaApp.instance.appOrSystemLanguageCode) -> Namespace.TALK.code()
UserAliasData.valueFor(WikipediaApp.instance.appOrSystemLanguageCode) -> Namespace.USER.code()
UserTalkAliasData.valueFor(WikipediaApp.instance.appOrSystemLanguageCode) -> Namespace.USER_TALK.code()
else -> -1
}
}

inner class Item constructor(val type: Int, val filterCode: String, val imageRes: Int? = null) {
fun isEnabled(): Boolean {
if (type == FILTER_TYPE_WIKI) {
return Prefs.userContribFilterLangCode == filterCode
}
val excludedNsFilter = Prefs.userContribFilterExcludedNs
if (filterCode == getString(R.string.user_contrib_filter_all)) {
return NAMESPACE_LIST.find { excludedNsFilter.contains(it) } == null
}
return !excludedNsFilter.contains(getNamespaceCode(filterCode))
}
}

companion object {
private const val VIEW_TYPE_HEADER = 0
private const val VIEW_TYPE_ITEM = 1
private const val VIEW_TYPE_ADD_LANGUAGE = 2
const val FILTER_TYPE_WIKI = 0
const val FILTER_TYPE_NAMESPACE = 1
val NAMESPACE_LIST = listOf(Namespace.MAIN.code(), Namespace.TALK.code(), Namespace.USER.code(), Namespace.USER_TALK.code())

fun newIntent(context: Context): Intent {
return Intent(context, UserContribFilterActivity::class.java)
}
}
}
@@ -0,0 +1,84 @@
package org.wikipedia.usercontrib

import android.content.Context
import android.graphics.Typeface
import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.core.view.isVisible
import androidx.core.widget.ImageViewCompat
import org.wikipedia.Constants
import org.wikipedia.R
import org.wikipedia.WikipediaApp
import org.wikipedia.databinding.ItemUserContribFilterBinding
import org.wikipedia.search.SearchFragment
import org.wikipedia.util.DimenUtil
import org.wikipedia.util.ResourceUtil
import org.wikipedia.views.ViewUtil

class UserContribFilterItemView constructor(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) {

interface Callback {
fun onSelected(item: UserContribFilterActivity.Item?)
}

private var item: UserContribFilterActivity.Item? = null
private var binding = ItemUserContribFilterBinding.inflate(LayoutInflater.from(context), this)
private val labelTypeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
var callback: Callback? = null

init {
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DimenUtil.roundedDpToPx(48f))
setBackgroundResource(ResourceUtil.getThemedAttributeId(context, R.attr.selectableItemBackground))
setOnClickListener {
callback?.onSelected(item)
}
}

fun setContents(item: UserContribFilterActivity.Item) {
this.item = item
binding.itemTitle.text = WikipediaApp.instance.languageState.getWikiLanguageName(item.filterCode)
binding.itemCheck.isVisible = item.isEnabled()

if (item.type == UserContribFilterActivity.FILTER_TYPE_WIKI) {
getTitleCodeFor(item.filterCode)?.let {
binding.languageCode.text = it
binding.languageCode.visibility = View.VISIBLE
ViewUtil.formatLangButton(binding.languageCode, it, SearchFragment.LANG_BUTTON_TEXT_SIZE_SMALLER, SearchFragment.LANG_BUTTON_TEXT_SIZE_LARGER)
} ?: run {
binding.languageCode.visibility = View.GONE
}
binding.itemCheck.setImageResource(R.drawable.ic_baseline_radio_button_checked_24)
} else {
binding.languageCode.visibility = View.GONE
binding.itemCheck.setImageResource(R.drawable.ic_check_borderless)
}

item.imageRes?.let {
binding.itemLogo.setImageResource(it)
binding.itemLogo.visibility = View.VISIBLE
} ?: run {
binding.itemLogo.visibility = if (binding.languageCode.isVisible) View.GONE else View.INVISIBLE
}
}

fun setSingleLabel(text: String) {
binding.languageCode.visibility = View.GONE
binding.itemLogo.visibility = View.VISIBLE
binding.itemLogo.setImageResource(R.drawable.ic_mode_edit_themed_24dp)
binding.itemCheck.visibility = View.GONE
binding.itemTitle.setTextColor(ResourceUtil.getThemedColorStateList(context, R.attr.colorAccent))
binding.itemTitle.text = text.uppercase()
binding.itemTitle.typeface = labelTypeface
binding.itemTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f)
ImageViewCompat.setImageTintList(binding.itemLogo, ResourceUtil.getThemedColorStateList(context, R.attr.colorAccent))
}

private fun getTitleCodeFor(itemCode: String): String? {
return if (itemCode == Constants.WIKI_CODE_COMMONS || itemCode == Constants.WIKI_CODE_WIKIDATA) null
else itemCode
}
}

0 comments on commit 7731d86

Please sign in to comment.