Skip to content

[Contributions dashboard] app icon #5055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6827f0a
- initial work and test work
Williamrai Oct 21, 2024
a73f869
- adds list preference for setting app icon
Williamrai Oct 22, 2024
1ea4364
- fixes both app icon showing on the home screen
Williamrai Oct 22, 2024
ad68a6f
- adds a condition for showing donor icon
Williamrai Oct 22, 2024
2b24984
- fixes CI issue
Williamrai Oct 22, 2024
84e928e
Merge branch 'contributions-dashboard-design' into app-icon-contribut…
Williamrai Oct 22, 2024
208fa41
- adds Bottom sheet dialog for App icon
Williamrai Oct 23, 2024
f4195a5
- modifies AppIconDialog class to support API 21 for setting foregrou…
Williamrai Oct 24, 2024
b8bde54
- adds logic to show/hide change app icon
Williamrai Oct 24, 2024
123d86b
- fixes CI issue
Williamrai Oct 24, 2024
734e9ae
- adds donor benefit icon
Williamrai Oct 28, 2024
07f70ed
- replaces png with svg donor benefit launcher icon
Williamrai Oct 28, 2024
46f7758
Merge branch 'contributions-dashboard-design' into app-icon-contribut…
Williamrai Oct 30, 2024
a99f2b2
- code and ui fixes
Williamrai Oct 30, 2024
1cb3e47
- ci fix
Williamrai Oct 30, 2024
2818789
- removes displayName from launcherIcon
Williamrai Oct 31, 2024
c105c6f
- adds missing logic for showing "App Icon" setting
Williamrai Nov 5, 2024
6db7847
- replaces icon and removes unused resource
Williamrai Nov 5, 2024
9c5ae53
Merge branch 'main' into app-icon-contributions-dashboard-design
Williamrai Nov 7, 2024
bac9e89
Merge branch 'contributions-dashboard-design' into app-icon-contribut…
Williamrai Nov 7, 2024
ce951f9
Merge branch 'contributions-dashboard-design' into app-icon-contribut…
cooltey Nov 9, 2024
59dc73d
- code fixes
Williamrai Nov 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
android:fullBackupContent="@xml/full_backup_rules"
android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true"
android:icon="@mipmap/launcher"
android:label="@string/app_name"
android:name=".WikipediaApp"
android:theme="@style/AppTheme">
Expand All @@ -90,6 +89,11 @@
android:name=".main.MainActivity"
android:windowSoftInputMode="adjustResize"
android:theme="@style/AppTheme.Splash"
android:exported="true"/>
<activity-alias
android:name=".DefaultIcon"
android:targetActivity=".main.MainActivity"
android:icon="@mipmap/launcher"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand All @@ -102,7 +106,25 @@
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="wikipedia" />
</intent-filter>
</activity>
</activity-alias>
<activity-alias
android:name=".DonorIcon"
android:icon="@mipmap/ic_launcher_donor_benefit"
android:targetActivity=".main.MainActivity"
android:exported="true"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="wikipedia" />
</intent-filter>
</activity-alias>
<activity
android:name=".page.PageActivity"
android:windowSoftInputMode="stateAlwaysHidden|adjustPan"
Expand Down
57 changes: 57 additions & 0 deletions app/src/main/java/org/wikipedia/LauncherController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.wikipedia

import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import org.wikipedia.settings.Prefs

object LauncherController {

fun setIcon(icon: LauncherIcon) {
val context = WikipediaApp.instance.applicationContext
val packageManager = context.packageManager
LauncherIcon.entries.forEach { launcherIcon ->
packageManager.setComponentEnabledSetting(
launcherIcon.getComponentName(context),
if (launcherIcon == icon) PackageManager.COMPONENT_ENABLED_STATE_ENABLED else
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
)
}
}
}

enum class LauncherIcon(
val key: String,
val background: Int,
val foreground: Int,
val label: Int,
var isSelected: Boolean = false
) {
DEFAULT(
key = "DefaultIcon",
background = R.drawable.launcher_background,
foreground = R.drawable.launcher_foreground,
label = R.string.app_name
),
DONOR(
key = "DonorIcon",
background = R.drawable.launcher_background,
foreground = R.drawable.ic_launcher_donor_benefit_foreground,
label = R.string.app_name
);

fun getComponentName(context: Context): ComponentName {
return ComponentName(context.packageName, "org.wikipedia.$key")
}

companion object {
fun initialValues(): List<LauncherIcon> {
val savedAppIcon = Prefs.currentSelectedAppIcon ?: DEFAULT.key
entries.forEach { icon ->
icon.isSelected = icon.key == savedAppIcon
}
return entries
}
}
}
140 changes: 140 additions & 0 deletions app/src/main/java/org/wikipedia/settings/AppIconDialog.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package org.wikipedia.settings

import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.google.android.flexbox.AlignItems
import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexboxLayoutManager
import com.google.android.flexbox.JustifyContent
import org.wikipedia.LauncherController
import org.wikipedia.LauncherIcon
import org.wikipedia.R
import org.wikipedia.appshortcuts.AppShortcuts
import org.wikipedia.databinding.DialogAppIconBinding
import org.wikipedia.databinding.ItemAppIconBinding
import org.wikipedia.page.ExtendedBottomSheetDialogFragment
import org.wikipedia.util.DimenUtil
import org.wikipedia.util.FeedbackUtil
import org.wikipedia.util.ResourceUtil

class AppIconDialog : ExtendedBottomSheetDialogFragment() {
private var _binding: DialogAppIconBinding? = null
private val binding get() = _binding!!

private val appIconAdapter: AppIconAdapter by lazy {
AppIconAdapter().apply {
onItemClickListener { selectedIcon ->
Prefs.currentSelectedAppIcon = selectedIcon.key
LauncherController.setIcon(selectedIcon)
AppShortcuts.setShortcuts(requireContext())
updateIcons(selectedIcon)
dismiss()
FeedbackUtil.makeSnackbar(
requireActivity(),
"App icon changed successfully.").show()
}
}
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = DialogAppIconBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
}

private fun setupRecyclerView() {
val layoutManager = FlexboxLayoutManager(requireContext()).apply {
flexDirection = FlexDirection.ROW
justifyContent = JustifyContent.CENTER
alignItems = AlignItems.CENTER
}
binding.appIconRecyclerView.apply {
this.layoutManager = layoutManager
adapter = appIconAdapter
}
appIconAdapter.updateItems(LauncherIcon.initialValues())
}

private fun updateIcons(selectedIcon: LauncherIcon) {
val currentSelectedIcon = if (Prefs.currentSelectedAppIcon != null) Prefs.currentSelectedAppIcon
else selectedIcon.key

LauncherIcon.entries.forEach {
it.isSelected = it.key == currentSelectedIcon
}
appIconAdapter.updateItems(LauncherIcon.entries)
}

private class AppIconAdapter : RecyclerView.Adapter<AppIconAdapter.AppIconViewHolder>() {
private var list = mutableListOf<LauncherIcon>()
private var onItemClickListener: ((LauncherIcon) -> Unit)? = null

fun onItemClickListener(onItemClickListener: (LauncherIcon) -> Unit) {
this.onItemClickListener = onItemClickListener
}

fun updateItems(newList: List<LauncherIcon>) {
list.clear()
list.addAll(newList)
notifyItemRangeChanged(0, list.size)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppIconViewHolder {
val view = ItemAppIconBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return AppIconViewHolder(view)
}

override fun getItemCount(): Int = list.size

override fun onBindViewHolder(holder: AppIconViewHolder, position: Int) {
val item = list[position]
holder.bind(item)
}

private inner class AppIconViewHolder(val binding: ItemAppIconBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: LauncherIcon) {
binding.appIcon.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
foreground = ContextCompat.getDrawable(binding.root.context, item.foreground)
} else {
setImageDrawable(ContextCompat.getDrawable(binding.root.context, item.foreground))
}
background = ContextCompat.getDrawable(binding.root.context, item.background)
setOnClickListener {
onItemClickListener?.invoke(item)
}
val strokeColor = if (item.isSelected) {
R.attr.progressive_color
} else R.attr.border_color
val newStrokeWidth = if (item.isSelected) 2f else 1f
this.strokeColor = ResourceUtil.getThemedColorStateList(context, strokeColor)
this.strokeWidth = DimenUtil.dpToPx(newStrokeWidth)
}
}
}
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
}

companion object {
fun newInstance(): AppIconDialog {
return AppIconDialog()
}
}
}
5 changes: 5 additions & 0 deletions app/src/main/java/org/wikipedia/settings/Prefs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import okhttp3.Cookie
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.logging.HttpLoggingInterceptor
import org.wikipedia.BuildConfig
import org.wikipedia.LauncherIcon
import org.wikipedia.R
import org.wikipedia.WikipediaApp
import org.wikipedia.analytics.SessionData
Expand Down Expand Up @@ -754,4 +755,8 @@ object Prefs {
var contributionsDashboardEntryDialogShown
get() = PrefsIoUtil.getBoolean(R.string.preference_key_contributions_dashboard_entry_dialog_shown, false)
set(value) = PrefsIoUtil.setBoolean(R.string.preference_key_contributions_dashboard_entry_dialog_shown, value)

var currentSelectedAppIcon
get() = PrefsIoUtil.getString(R.string.preference_key_current_selected_app_icon, LauncherIcon.DEFAULT.key)
set(value) = PrefsIoUtil.setString(R.string.preference_key_current_selected_app_icon, value)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ import org.wikipedia.Constants
import org.wikipedia.R
import org.wikipedia.WikipediaApp
import org.wikipedia.auth.AccountUtil
import org.wikipedia.donate.DonorStatus
import org.wikipedia.feed.configure.ConfigureActivity
import org.wikipedia.login.LoginActivity
import org.wikipedia.page.ExclusiveBottomSheetPresenter
import org.wikipedia.readinglist.sync.ReadingListSyncAdapter
import org.wikipedia.settings.languages.WikipediaLanguagesActivity
import org.wikipedia.theme.ThemeFittingRoomActivity
import org.wikipedia.usercontrib.ContributionsDashboardHelper
import org.wikipedia.util.FeedbackUtil

/** UI code for app settings used by PreferenceFragment. */
Expand Down Expand Up @@ -47,6 +50,16 @@ internal class SettingsPreferenceLoader(fragment: PreferenceFragmentCompat) : Ba
true
}
}

if (ContributionsDashboardHelper.contributionsDashboardEnabled && DonorStatus.donorStatus() == DonorStatus.DONOR) {
findPreference(R.string.preference_key_app_icon).onPreferenceClickListener = Preference.OnPreferenceClickListener {
ExclusiveBottomSheetPresenter.show(fragment.parentFragmentManager, AppIconDialog.newInstance())
true
}
} else {
findPreference(R.string.preference_key_app_icon).isVisible = false
}

findPreference(R.string.preference_key_about_wikipedia_app).onPreferenceClickListener = Preference.OnPreferenceClickListener {
activity.startActivity(Intent(activity, AboutActivity::class.java))
true
Expand Down
21 changes: 21 additions & 0 deletions app/src/main/res/drawable/ic_launcher_donor_benefit_foreground.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This icon looks very different from our standard "W" launcher icon. (Not just the "heart" shape, but the size and font of the "W" is different from the default.)
Where did it come from, and how was it generated?
Ideally the icon should be the same "W" as the default, with the "heart" in the same spot as the "star" shape in our Beta/Alpha/Dev icons.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I exported this from the Figma and used the Android Resource manager to import this. I have requested design for a new app icon similar to the alpha icons.

android:width="108dp"
android:height="108dp"
android:viewportWidth="28"
android:viewportHeight="28">
<group android:scaleX="0.91"
android:scaleY="0.91"
android:translateX="1.26"
android:translateY="1.26">
<path
android:pathData="M18.6,12.066L18.358,11.846C17.5,11.067 16.933,10.554 16.933,9.924C16.933,9.411 17.337,9.007 17.85,9.007C18.14,9.007 18.418,9.142 18.6,9.356C18.782,9.142 19.06,9.007 19.35,9.007C19.863,9.007 20.267,9.411 20.267,9.924C20.267,10.554 19.7,11.067 18.842,11.847L18.6,12.066Z"
android:fillColor="#DD3333"/>
<group>
<clip-path
android:pathData="M21,10.57C20.862,11.81 19.814,12.749 18.566,12.75C17.214,12.749 16.118,11.653 16.117,10.3C16.118,9.27 16.763,8.351 17.732,8H7V20H21V10.57Z"/>
<path
android:pathData="M20.647,10.333C20.647,10.383 20.632,10.428 20.603,10.469C20.573,10.509 20.542,10.53 20.506,10.53C20.217,10.559 19.98,10.657 19.796,10.824C19.612,10.99 19.423,11.308 19.227,11.775L16.235,18.856C16.215,18.922 16.161,18.955 16.07,18.955C15.999,18.955 15.945,18.922 15.905,18.856L14.228,15.171L12.299,18.856C12.26,18.922 12.205,18.955 12.134,18.955C12.048,18.955 11.991,18.922 11.964,18.856L9.025,11.775C8.842,11.335 8.648,11.028 8.444,10.854C8.241,10.68 7.957,10.571 7.594,10.53C7.563,10.53 7.533,10.513 7.506,10.478C7.478,10.444 7.464,10.404 7.464,10.359C7.464,10.243 7.495,10.186 7.558,10.186C7.82,10.186 8.094,10.198 8.38,10.223C8.646,10.249 8.896,10.261 9.13,10.261C9.369,10.261 9.651,10.249 9.975,10.223C10.315,10.199 10.616,10.186 10.878,10.186C10.941,10.186 10.972,10.243 10.972,10.359C10.972,10.473 10.952,10.531 10.914,10.531C10.652,10.552 10.446,10.622 10.295,10.74C10.144,10.859 10.069,11.015 10.069,11.209C10.069,11.308 10.1,11.431 10.163,11.578L12.592,17.34L13.971,14.604L12.686,11.775C12.455,11.271 12.265,10.944 12.117,10.798C11.969,10.653 11.744,10.563 11.442,10.53C11.414,10.53 11.389,10.513 11.363,10.478C11.337,10.444 11.325,10.404 11.325,10.359C11.325,10.243 11.352,10.186 11.407,10.186C11.669,10.186 11.909,10.198 12.128,10.223C12.339,10.249 12.564,10.261 12.803,10.261C13.037,10.261 13.285,10.249 13.547,10.223C13.817,10.199 14.083,10.186 14.345,10.186C14.408,10.186 14.439,10.243 14.439,10.359C14.439,10.473 14.42,10.531 14.381,10.531C13.857,10.569 13.595,10.725 13.595,11C13.595,11.123 13.655,11.314 13.777,11.572L14.627,13.384L15.472,11.726C15.589,11.492 15.648,11.295 15.648,11.134C15.648,10.756 15.386,10.555 14.862,10.53C14.814,10.53 14.791,10.473 14.791,10.358C14.791,10.317 14.803,10.278 14.826,10.241C14.85,10.203 14.874,10.185 14.897,10.185C15.085,10.185 15.316,10.197 15.589,10.222C15.851,10.248 16.067,10.26 16.235,10.26C16.356,10.26 16.534,10.249 16.768,10.228C17.065,10.2 17.314,10.185 17.513,10.185C17.559,10.185 17.583,10.234 17.583,10.332C17.583,10.464 17.54,10.529 17.454,10.529C17.149,10.562 16.903,10.651 16.718,10.795C16.532,10.939 16.301,11.265 16.024,11.774L14.897,13.964L16.423,17.229L18.676,11.726C18.754,11.525 18.793,11.34 18.793,11.172C18.793,10.769 18.531,10.556 18.007,10.53C17.959,10.53 17.936,10.473 17.936,10.358C17.936,10.242 17.971,10.185 18.042,10.185C18.233,10.185 18.461,10.197 18.723,10.222C18.965,10.248 19.169,10.26 19.333,10.26C19.506,10.26 19.705,10.248 19.931,10.222C20.166,10.198 20.377,10.185 20.565,10.185C20.619,10.185 20.647,10.234 20.647,10.332V10.333Z"
android:fillColor="#333333"/>
</group>
</group>
</vector>
48 changes: 48 additions & 0 deletions app/src/main/res/layout/dialog_app_icon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">

<TextView
android:id="@+id/app_icon_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:layout_marginStart="16dp"
android:fontFamily="sans-serif-medium"
android:gravity="center_vertical"
android:text="@string/contributions_dashboard_app_icon_title"
android:textColor="?attr/primary_color"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

<TextView
android:id="@+id/app_icon_sub_title"
style="@style/Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:textAllCaps="true"
android:text="@string/contributions_dashboard_app_icon_subtitle"
android:textColor="?attr/primary_color"
app:layout_constraintBaseline_toBaselineOf="@+id/app_icon_title"
app:layout_constraintBottom_toBottomOf="@+id/app_icon_title"
app:layout_constraintStart_toEndOf="@+id/app_icon_title"
app:layout_constraintTop_toTopOf="@+id/app_icon_title" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/appIconRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/app_icon_title"
tools:itemCount="2"
tools:listitem="@layout/item_app_icon"
/>

</androidx.constraintlayout.widget.ConstraintLayout>
15 changes: 15 additions & 0 deletions app/src/main/res/layout/item_app_icon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.imageview.ShapeableImageView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/app_icon"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_margin="12dp"
android:scaleType="centerCrop"
android:padding="2dp"
app:shapeAppearanceOverlay="@style/CircularImageView"
app:strokeWidth="2dp"
xmlns:tools="http://schemas.android.com/tools"
tools:srcCompat="@tools:sample/avatars">

</com.google.android.material.imageview.ShapeableImageView>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_donor_benefit_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_donor_benefit_foreground"/>
</adaptive-icon>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Loading