Skip to content

Commit

Permalink
Upgrade to Material3 themes (ankidroid#14596)
Browse files Browse the repository at this point in the history
* upgrade to Material themes

this means some changes in text appearance, color, margins, roundness, among other things.

please note that the app won't magically look like a modern Material app just with this change. This is just jumping in the pool before start swimming

* refactor: slide style

* upgrade switches to Material

* refactor: remove largeButtonFilledStyle

* fix: broken buttons with material theme

* refactor: remove NoBackgroundButton

Use Widget.Material3.Button.TextButton instead

* refactor: replace crash report dialog style

* refactor: remove some unused styles

* fix: align FAB buttons

* fix: get some colors back to what they were

* upgrade permissions screen to material

* set appBar color with a custom attribute

So the colorPrimary can be really a primary color

* chore: upgrade com.google.android.material to 1.10.0

closes ankidroid#14518

* fix: reviewer "show answer" button color

In Material, it used `colorPrimary` as default

I left a FIXME at Onboarding::onQuestionShown because idk when someone will work on it again, and I expect that to be changed anyway when the desktop reviewer is ported

* refactor: remove "compat" themes

Nowadays, we don't need this kind of approach.

* refactor: replace getColorFromAttr

`MaterialColors.getColor` do the same and I prefer using common library methods, so people can reuse what they know from other projects

* change browser column selector height

* docs: remove comment
  • Loading branch information
BrayanDSO authored Nov 1, 2023
1 parent 7d15caa commit 135615d
Show file tree
Hide file tree
Showing 42 changed files with 146 additions and 261 deletions.
4 changes: 1 addition & 3 deletions AnkiDroid/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,7 @@ dependencies {
implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.webkit:webkit:1.8.0'
// Note: the design support library can be quite buggy, so test everything thoroughly before updating it
// Changing the version from 1.8.0 to 1.7.0 because the item in navigation drawer is getting bold unnecessarily
implementation 'com.google.android.material:material:1.7.0'
implementation 'com.google.android.material:material:1.10.0'
implementation 'com.vanniktech:android-image-cropper:4.5.0'
implementation 'org.nanohttpd:nanohttpd:2.3.1'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0"
Expand Down
10 changes: 5 additions & 5 deletions AnkiDroid/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@
</activity>
<activity
android:name="com.ichi2.anki.DeckPicker"
android:theme="@style/Theme_Dark_Compat.Launcher"
android:theme="@style/Theme_Dark.Launcher"
android:exported="false"
android:configChanges="keyboardHidden|orientation|screenSize"
/>
Expand Down Expand Up @@ -230,7 +230,7 @@
<activity
android:name="com.ichi2.anki.CardBrowser"
android:label="@string/card_browser"
android:theme="@style/Theme_Dark_Compat.Launcher"
android:theme="@style/Theme_Dark.Launcher"
android:exported="true"
android:configChanges="keyboardHidden|orientation|screenSize"
android:parentActivityName=".DeckPicker"
Expand Down Expand Up @@ -261,7 +261,7 @@
<activity
android:name="com.ichi2.anki.Reviewer"
android:exported="true"
android:theme="@style/Theme_Dark_Compat.Launcher"
android:theme="@style/Theme_Dark.Launcher"
android:configChanges="keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize"
android:parentActivityName=".DeckPicker">
Expand Down Expand Up @@ -315,7 +315,7 @@
<activity
android:name="com.ichi2.anki.NoteEditor"
android:label="@string/fact_adder_intent_title"
android:theme="@style/Theme_Dark_Compat.Launcher"
android:theme="@style/Theme_Dark.Launcher"
android:exported="true"
android:configChanges="keyboardHidden|orientation|screenSize"
>
Expand All @@ -336,7 +336,7 @@
android:theme="@style/Base.Theme.AppCompat" />
<activity
android:name="com.ichi2.anki.analytics.AnkiDroidCrashReportDialog"
android:theme="@style/Theme.CrashReportDialog"
android:theme="@android:style/Theme.DeviceDefault.Dialog"
android:process=":acra"
android:launchMode="singleInstance"
android:excludeFromRecents="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ abstract class AbstractFlashcardViewer :
private var mCardFrame: FrameLayout? = null
private var mTouchLayer: FrameLayout? = null
protected var answerField: FixedEditText? = null
protected var flipCardLayout: LinearLayout? = null
protected var flipCardLayout: FrameLayout? = null
private var easeButtonsLayout: LinearLayout? = null

@KotlinCleanup("internal for AnkiDroidJsApi")
Expand Down Expand Up @@ -904,8 +904,7 @@ abstract class AbstractFlashcardViewer :
easeButton3!!.hideNextReviewTime()
easeButton4!!.hideNextReviewTime()
}
val flipCard = findViewById<Button>(R.id.flip_card)
flipCardLayout = findViewById<LinearLayout>(R.id.flashcard_layout_flip)
flipCardLayout = findViewById(R.id.flashcard_layout_flip)
flipCardLayout?.let { layout ->
if (minimalClickSpeed == 0) {
layout.setOnClickListener(mFlipCardListener)
Expand All @@ -929,7 +928,7 @@ abstract class AbstractFlashcardViewer :
}
}
if (animationEnabled()) {
flipCard.setBackgroundResource(getResFromAttr(this, R.attr.hardButtonRippleRef))
flipCardLayout?.setBackgroundResource(getResFromAttr(this, R.attr.hardButtonRippleRef))
}
if (!mButtonHeightSet && mRelativeButtonSize != 100) {
val params = flipCardLayout!!.layoutParams
Expand Down
5 changes: 3 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.PendingIntentCompat
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import com.google.android.material.color.MaterialColors
import com.ichi2.anim.ActivityTransitionAnimation
import com.ichi2.anim.ActivityTransitionAnimation.Direction
import com.ichi2.anim.ActivityTransitionAnimation.Direction.*
Expand Down Expand Up @@ -367,8 +368,8 @@ open class AnkiActivity : AppCompatActivity, SimpleMessageDialogListener {
)
return
}
val toolbarColor = Themes.getColorFromAttr(this, android.R.attr.colorPrimary)
val navBarColor = Themes.getColorFromAttr(this, R.attr.customTabNavBarColor)
val toolbarColor = MaterialColors.getColor(this, R.attr.appBarColor, 0)
val navBarColor = MaterialColors.getColor(this, R.attr.customTabNavBarColor, 0)
val colorSchemeParams = CustomTabColorSchemeParams.Builder()
.setToolbarColor(toolbarColor)
.setNavigationBarColor(navBarColor)
Expand Down
4 changes: 2 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/CardBrowser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import androidx.annotation.VisibleForTesting
import androidx.appcompat.widget.SearchView
import androidx.core.content.edit
import anki.collection.OpChanges
import com.google.android.material.color.MaterialColors
import com.google.android.material.snackbar.Snackbar
import com.ichi2.anim.ActivityTransitionAnimation
import com.ichi2.anki.CollectionManager.TR
Expand Down Expand Up @@ -71,7 +72,6 @@ import com.ichi2.compat.Compat
import com.ichi2.libanki.*
import com.ichi2.libanki.SortOrder.NoOrdering
import com.ichi2.libanki.SortOrder.UseCollectionOrdering
import com.ichi2.themes.Themes.getColorFromAttr
import com.ichi2.ui.CardBrowserSearchView
import com.ichi2.ui.FixedTextView
import com.ichi2.utils.*
Expand Down Expand Up @@ -1956,7 +1956,7 @@ open class CardBrowser :
col.text = card.getColumnHeaderText(fromKeys[i]) // set text for column
}
// set card's background color
val backgroundColor: Int = getColorFromAttr(this@CardBrowser, card.color)
val backgroundColor: Int = MaterialColors.getColor(this@CardBrowser, card.color, 0)
v.setBackgroundColor(backgroundColor)
// setup checkbox to change color in multi-select mode
val checkBox = v.findViewById<CheckBox>(R.id.card_checkbox)
Expand Down
4 changes: 2 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/FieldEditText.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ import androidx.core.view.OnReceiveContentListener
import androidx.core.view.ViewCompat
import androidx.core.view.inputmethod.EditorInfoCompat
import androidx.core.view.inputmethod.InputConnectionCompat
import com.google.android.material.color.MaterialColors
import com.ichi2.anki.preferences.sharedPrefs
import com.ichi2.anki.servicelayer.NoteService
import com.ichi2.themes.Themes.getColorFromAttr
import com.ichi2.ui.FixedEditText
import com.ichi2.utils.ClipboardUtil.IMAGE_MIME_TYPES
import com.ichi2.utils.ClipboardUtil.getImageUri
Expand Down Expand Up @@ -164,7 +164,7 @@ class FieldEditText : FixedEditText, NoteService.NoteField {
* Modify the style of this view to represent a duplicate field.
*/
fun setDupeStyle() {
setBackgroundColor(getColorFromAttr(context, R.attr.duplicateColor))
setBackgroundColor(MaterialColors.getColor(context, R.attr.duplicateColor, 0))
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import androidx.core.graphics.drawable.IconCompat
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.ClosableDrawerLayout
import androidx.drawerlayout.widget.DrawerLayout
import com.google.android.material.color.MaterialColors
import com.google.android.material.navigation.NavigationView
import com.ichi2.anim.ActivityTransitionAnimation.Direction.*
import com.ichi2.anki.dialogs.HelpDialog
Expand All @@ -46,7 +47,6 @@ import com.ichi2.anki.preferences.sharedPrefs
import com.ichi2.anki.workarounds.FullDraggableContainerFix
import com.ichi2.compat.CompatHelper
import com.ichi2.libanki.CardId
import com.ichi2.themes.Themes
import com.ichi2.utils.HandlerUtils
import com.ichi2.utils.KotlinCleanup
import timber.log.Timber
Expand Down Expand Up @@ -120,9 +120,10 @@ abstract class NavigationDrawerActivity :
// Force transparent status bar with primary dark color underlaid so that the drawer displays under status bar
window.statusBarColor = getColor(R.color.transparent)
mDrawerLayout.setStatusBarBackgroundColor(
Themes.getColorFromAttr(
MaterialColors.getColor(
this,
android.R.attr.colorPrimary
R.attr.appBarColor,
0
)
)
// Setup toolbar and hamburger
Expand Down
18 changes: 10 additions & 8 deletions AnkiDroid/src/main/java/com/ichi2/anki/NoteEditor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import androidx.core.content.edit
import androidx.core.content.res.ResourcesCompat
import androidx.core.text.HtmlCompat
import anki.config.ConfigKey
import com.google.android.material.color.MaterialColors
import com.google.android.material.snackbar.Snackbar
import com.ichi2.anim.ActivityTransitionAnimation
import com.ichi2.anim.ActivityTransitionAnimation.Direction.*
Expand Down Expand Up @@ -86,7 +87,6 @@ import com.ichi2.libanki.Note.ClozeUtils
import com.ichi2.libanki.Note.DupeOrEmpty
import com.ichi2.libanki.Notetypes.Companion.NOT_FOUND_NOTE_TYPE
import com.ichi2.libanki.exception.ConfirmModSchemaException
import com.ichi2.themes.Themes
import com.ichi2.utils.*
import com.ichi2.widget.WidgetStatus
import org.json.JSONArray
Expand Down Expand Up @@ -260,12 +260,13 @@ class NoteEditor : AnkiActivity(), DeckSelectionListener, SubtitleListener, Tags
}
// Sets the background and icon color of toolbar respectively.
setBackgroundColor(
Themes.getColorFromAttr(
MaterialColors.getColor(
this@NoteEditor,
R.attr.toolbarBackgroundColor
R.attr.toolbarBackgroundColor,
0
)
)
setIconColor(Themes.getColorFromAttr(this@NoteEditor, R.attr.toolbarIconColor))
setIconColor(MaterialColors.getColor(this@NoteEditor, R.attr.toolbarIconColor, 0))
}
val mainView = findViewById<View>(android.R.id.content)
// Enable toolbar
Expand Down Expand Up @@ -1522,9 +1523,10 @@ class NoteEditor : AnkiActivity(), DeckSelectionListener, SubtitleListener, Tags
// Sets the background color of disabled EditText.
if (!enabled) {
editText.setBackgroundColor(
Themes.getColorFromAttr(
MaterialColors.getColor(
this@NoteEditor,
R.attr.editTextBackgroundColor
R.attr.editTextBackgroundColor,
0
)
)
}
Expand Down Expand Up @@ -1656,7 +1658,7 @@ class NoteEditor : AnkiActivity(), DeckSelectionListener, SubtitleListener, Tags

private fun addClozeButton(@DrawableRes drawableRes: Int, description: String, type: AddClozeType) {
val drawable = ResourcesCompat.getDrawable(resources, drawableRes, null)!!.apply {
setTint(Themes.getColorFromAttr(this@NoteEditor, R.attr.toolbarIconColor))
setTint(MaterialColors.getColor(this@NoteEditor, R.attr.toolbarIconColor, 0))
}
val button = toolbar.insertItem(0, drawable) { insertCloze(type) }.apply {
contentDescription = description
Expand Down Expand Up @@ -1718,7 +1720,7 @@ class NoteEditor : AnkiActivity(), DeckSelectionListener, SubtitleListener, Tags
// Let the user add more buttons (always at the end).
// Sets the add custom tag icon color.
val drawable = ResourcesCompat.getDrawable(resources, R.drawable.ic_add_toolbar_icon, null)
drawable!!.setTint(Themes.getColorFromAttr(this@NoteEditor, R.attr.toolbarIconColor))
drawable!!.setTint(MaterialColors.getColor(this@NoteEditor, R.attr.toolbarIconColor, 0))
val addButton = toolbar.insertItem(0, drawable) { displayAddToolbarDialog() }
addButton.contentDescription = resources.getString(R.string.add_toolbar_item)
TooltipCompat.setTooltipText(addButton, resources.getString(R.string.add_toolbar_item))
Expand Down
2 changes: 1 addition & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/Onboarding.kt
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ abstract class Onboarding<Feature>(
CustomMaterialTapTargetPromptBuilder(activityContext, ReviewerOnboardingEnum.SHOW_ANSWER)
.createRectangleWithDimmedBackground()
.setDismissedListener { onCreate() }
.setTarget(R.id.flip_card)
// FIXME .setTarget(R.id.flip_card)
.setPrimaryText(R.string.see_answer)
.setSecondaryText(R.string.see_answer_desc)
.show()
Expand Down
4 changes: 2 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/Reviewer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.MenuItemCompat
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
import com.google.android.material.color.MaterialColors
import com.google.android.material.snackbar.Snackbar
import com.ichi2.anim.ActivityTransitionAnimation
import com.ichi2.anim.ActivityTransitionAnimation.getInverseTransition
Expand Down Expand Up @@ -82,7 +83,6 @@ import com.ichi2.libanki.sched.CurrentQueueState
import com.ichi2.libanki.utils.TimeManager
import com.ichi2.themes.Themes
import com.ichi2.themes.Themes.currentTheme
import com.ichi2.themes.Themes.getColorFromAttr
import com.ichi2.utils.*
import com.ichi2.utils.HandlerUtils.getDefaultLooper
import com.ichi2.utils.Permissions.canRecordAudio
Expand Down Expand Up @@ -1238,7 +1238,7 @@ open class Reviewer :
// Show / hide the Action bar together with the status bar
val prefs = a.sharedPrefs()
val fullscreenMode = fromPreference(prefs)
a.window.statusBarColor = getColorFromAttr(a, android.R.attr.colorPrimary)
a.window.statusBarColor = MaterialColors.getColor(a, R.attr.appBarColor, 0)
val decorView = a.window.decorView
decorView.setOnSystemUiVisibilityChangeListener { flags: Int ->
val toolbar = a.findViewById<View>(R.id.toolbar)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class Toolbar : FrameLayout {
fun insertItem(@IdRes id: Int, @DrawableRes drawable: Int, block: () -> Unit): AppCompatImageButton {
// we use the light theme here to ensure the tint is black on both
// A null theme can be passed after colorControlNormal is defined (API 25)
val themeContext: Context = ContextThemeWrapper(context, R.style.Theme_Light_Compat)
val themeContext: Context = ContextThemeWrapper(context, R.style.Theme_Light)
val d = VectorDrawableCompat.create(context.resources, drawable, themeContext.theme)
return insertItem(id, d, block)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import android.os.SystemClock
import android.view.View
import android.widget.Chronometer
import androidx.annotation.VisibleForTesting
import com.google.android.material.color.MaterialColors
import com.ichi2.anki.R
import com.ichi2.libanki.Card
import com.ichi2.themes.Themes.getColorFromAttr

/**
* Responsible for pause/resume of the card timer and the UI element displaying the amount of time to answer a card
Expand Down Expand Up @@ -75,7 +75,7 @@ class AnswerTimer(private val cardTimer: Chronometer) {

private fun resetTimerUI(newCard: Card) {
// Set normal timer color
cardTimer.setTextColor(getColorFromAttr(context, android.R.attr.textColor))
cardTimer.setTextColor(MaterialColors.getColor(context, android.R.attr.textColor, 0))

cardTimer.base = elapsedRealTime
cardTimer.start()
Expand All @@ -85,7 +85,7 @@ class AnswerTimer(private val cardTimer: Chronometer) {
cardTimer.setOnChronometerTickListener { chronometer: Chronometer ->
val elapsed: Long = elapsedRealTime - chronometer.base
if (elapsed >= limit) {
chronometer.setTextColor(getColorFromAttr(context, R.attr.maxTimerColor))
chronometer.setTextColor(MaterialColors.getColor(context, R.attr.maxTimerColor, 0))
chronometer.stop()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ package com.ichi2.preferences

import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.SwitchCompat
import androidx.core.content.edit
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceViewHolder
import com.google.android.material.materialswitch.MaterialSwitch
import com.ichi2.anki.R

/**
Expand Down Expand Up @@ -59,15 +59,13 @@ class VersatileTextWithASwitchPreference(context: Context, attrs: AttributeSet?)
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)

val switch = holder.findViewById(R.id.switch_widget) as SwitchCompat

switch.isFocusable = canBeSwitchedOn
switch.isClickable = canBeSwitchedOn

switch.isChecked = preferences.getBoolean(switchKey, false)

switch.setOnCheckedChangeListener { _, checked ->
preferences.edit { putBoolean(switchKey, checked) }
with(holder.findViewById(R.id.switch_widget) as MaterialSwitch) {
isFocusable = canBeSwitchedOn
isClickable = canBeSwitchedOn
isChecked = preferences.getBoolean(switchKey, false)
setOnCheckedChangeListener { _, checked ->
preferences.edit { putBoolean(switchKey, checked) }
}
}
}

Expand Down
8 changes: 4 additions & 4 deletions AnkiDroid/src/main/java/com/ichi2/themes/Theme.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import com.ichi2.anki.R
enum class Theme(val id: String, @StyleRes val resId: Int, val isNightMode: Boolean) {
// IDs must correspond to the ones at @array/app_theme_values on res/values/constants.xml
// Follow system is "0", so it starts at "1"
LIGHT("1", R.style.Theme_Light_Compat, false),
PLAIN("2", R.style.Theme_Plain_Compat, false),
BLACK("3", R.style.Theme_Black_Compat, true),
DARK("4", R.style.Theme_Dark_Compat, true);
LIGHT("1", R.style.Theme_Light, false),
PLAIN("2", R.style.Theme_Light_Plain, false),
BLACK("3", R.style.Theme_Dark_Black, true),
DARK("4", R.style.Theme_Dark, true);

companion object {
val fallback: Theme
Expand Down
10 changes: 2 additions & 8 deletions AnkiDroid/src/main/java/com/ichi2/themes/Themes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import android.content.res.Configuration
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.fragment.app.Fragment
import com.google.android.material.color.MaterialColors
import com.ichi2.anki.AnkiDroidApp
import com.ichi2.anki.R
import com.ichi2.anki.preferences.sharedPrefs
Expand Down Expand Up @@ -103,13 +104,6 @@ object Themes {
return attrs
}

@JvmStatic // tests failed when removing, maybe try later
@ColorInt
fun getColorFromAttr(context: Context?, colorAttr: Int): Int {
val attrs = intArrayOf(colorAttr)
return getColorFromAttr(context!!, attrs)[0]
}

@JvmStatic // tests failed when removing, maybe try later
@ColorInt
fun getColorFromAttr(context: Context, attrs: IntArray): IntArray {
Expand All @@ -126,7 +120,7 @@ object Themes {
*/
@ColorInt
fun Fragment.getColorFromAttr(@AttrRes attribute: Int): Int {
return getColorFromAttr(requireContext(), attribute)
return MaterialColors.getColor(requireContext(), attribute, 0)
}

/**
Expand Down
Loading

0 comments on commit 135615d

Please sign in to comment.