Skip to content
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

Feature/switch night #2867

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion app/src/main/java/one/mixin/android/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ object Constants {

object Theme {
const val THEME_CURRENT_ID = "theme_current_id"
const val THEME_DEFAULT_ID = 0
const val THEME_LIGHT_ID = 0
const val THEME_NIGHT_ID = 1
const val THEME_AUTO_ID = 2
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ fun Context.isNightMode(): Boolean {
} else {
defaultSharedPreferences.getInt(
Constants.Theme.THEME_CURRENT_ID,
Constants.Theme.THEME_DEFAULT_ID
Constants.Theme.THEME_LIGHT_ID
) == Constants.Theme.THEME_NIGHT_ID
}
}
Expand All @@ -887,7 +887,7 @@ fun Context.getCurrentThemeId() = defaultSharedPreferences.getInt(
)

val defaultThemeId = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Constants.Theme.THEME_DEFAULT_ID
Constants.Theme.THEME_LIGHT_ID
} else {
Constants.Theme.THEME_AUTO_ID
}
Expand Down
193 changes: 160 additions & 33 deletions app/src/main/java/one/mixin/android/ui/setting/AppearanceFragment.kt
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
package one.mixin.android.ui.setting

import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import dagger.hilt.android.AndroidEntryPoint
import one.mixin.android.Constants
import one.mixin.android.MixinApplication
import one.mixin.android.R
import one.mixin.android.databinding.FragmentAppearanceBinding
import one.mixin.android.extension.alertDialogBuilder
import one.mixin.android.extension.defaultSharedPreferences
import one.mixin.android.extension.putInt
import one.mixin.android.extension.singleChoice
import one.mixin.android.extension.textColorResource
import one.mixin.android.session.Session
import one.mixin.android.ui.common.BaseFragment
import one.mixin.android.util.SystemUIManager
import one.mixin.android.util.TimeCache
import one.mixin.android.util.getLanguage
import one.mixin.android.util.getLocaleString
import one.mixin.android.util.isFollowSystem
import one.mixin.android.util.viewBinding
import one.mixin.android.vo.Fiats
import one.mixin.android.widget.theme.Coordinate
import one.mixin.android.widget.theme.NightModeSwitch.Companion.ANIM_DURATION
import one.mixin.android.widget.theme.ThemeActivity
import timber.log.Timber
import java.util.Locale

@AndroidEntryPoint
Expand All @@ -41,49 +48,80 @@ class AppearanceFragment : BaseFragment(R.layout.fragment_appearance) {
}

private val binding by viewBinding(FragmentAppearanceBinding::bind)
private val androidQ = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
private val androidS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
private val systemNightMode by lazy {
MixinApplication.appContext.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
}
private val localNightModeState by lazy {
defaultSharedPreferences.getInt(
Constants.Theme.THEME_CURRENT_ID,
if (!androidQ) {
Constants.Theme.THEME_LIGHT_ID
} else {
Constants.Theme.THEME_AUTO_ID
}
)
}
private var lastNightModeState: Int? = null
private var switchTask: (() -> Unit)? = null

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.apply {
titleView.leftIb.setOnClickListener {
activity?.onBackPressedDispatcher?.onBackPressed()
}
nightModeRl.setOnClickListener {
nightModeSwitch.switch()
}
nightModeTv.setText(R.string.Theme)
val currentId = defaultSharedPreferences.getInt(
Constants.Theme.THEME_CURRENT_ID,
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Constants.Theme.THEME_DEFAULT_ID
nightModeSwitch.initState(localNightModeState)
nightModeSwitch.setOnSwitchListener { state ->
if (lastNightModeState == null) lastNightModeState = localNightModeState
if (!isAdded || state == lastNightModeState) return@setOnSwitchListener
Timber.e("$state $lastNightModeState")
val currentNightMode = if (lastNightModeState == Constants.Theme.THEME_AUTO_ID) {
systemNightMode
} else {
Constants.Theme.THEME_AUTO_ID
lastNightModeState == Constants.Theme.THEME_NIGHT_ID
}
)
nightModeDescTv.text = resources.getStringArray(R.array.setting_night_array_oreo)[currentId]
nightModeRl.setOnClickListener {
singleChoice(
resources.getString(R.string.Theme),
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
R.array.setting_night_array
} else {
R.array.setting_night_array_oreo
},
currentId
) { dialog, index ->
val changed = index != currentId
defaultSharedPreferences.putInt(Constants.Theme.THEME_CURRENT_ID, index)
AppCompatDelegate.setDefaultNightMode(
when (index) {
Constants.Theme.THEME_DEFAULT_ID -> AppCompatDelegate.MODE_NIGHT_NO
Constants.Theme.THEME_NIGHT_ID -> AppCompatDelegate.MODE_NIGHT_YES
Constants.Theme.THEME_AUTO_ID -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
else -> AppCompatDelegate.MODE_NIGHT_NO
}
)
dialog.dismiss()
if (changed) {
requireActivity().onBackPressed()
lastNightModeState = state
val targetNightMode = if (state == Constants.Theme.THEME_AUTO_ID) {
systemNightMode
} else {
state == Constants.Theme.THEME_NIGHT_ID
}
Timber.e("targetNightMode:$targetNightMode currentNightMode:$currentNightMode")
switchTask = if (lastNightModeState != localNightModeState) {
{
Timber.e("switchTask")
AppCompatDelegate.setDefaultNightMode(
when (state) {
Constants.Theme.THEME_LIGHT_ID -> AppCompatDelegate.MODE_NIGHT_NO
Constants.Theme.THEME_NIGHT_ID -> AppCompatDelegate.MODE_NIGHT_YES
Constants.Theme.THEME_AUTO_ID -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
else -> AppCompatDelegate.MODE_NIGHT_NO
}
)
defaultSharedPreferences.putInt(Constants.Theme.THEME_CURRENT_ID, state)
requireActivity().recreate()
}
} else {
null
}
(requireActivity() as ThemeActivity).run {
changeTheme(
getViewCoordinates(nightModeSwitch),
ANIM_DURATION,
!targetNightMode
) {
if (androidS) {
switchTask?.invoke()
}
}
}
syncTheme(targetNightMode)
}
val languageNames = resources.getStringArray(R.array.language_names)
languageDescTv.text = if (isFollowSystem()) {
Expand All @@ -92,19 +130,81 @@ class AppearanceFragment : BaseFragment(R.layout.fragment_appearance) {
languageNames[getLanguagePos()]
}
languageRl.setOnClickListener { showLanguageAlert() }
currentTv.text = getString(R.string.wallet_setting_currency_desc, Session.getFiatCurrency(), Fiats.getSymbol())
currentTv.text = getString(
R.string.wallet_setting_currency_desc,
Session.getFiatCurrency(),
Fiats.getSymbol()
)
currencyRl.setOnClickListener {
val currencyBottom = CurrencyBottomSheetDialogFragment.newInstance()
currencyBottom.callback = object : CurrencyBottomSheetDialogFragment.Callback {
override fun onCurrencyClick(currency: Currency) {
currentTv.text = getString(R.string.wallet_setting_currency_desc, currency.name, currency.symbol)
currentTv.text = getString(
R.string.wallet_setting_currency_desc,
currency.name,
currency.symbol
)
}
}
currencyBottom.showNow(parentFragmentManager, CurrencyBottomSheetDialogFragment.TAG)
}
}
}

override fun onDestroy() {
if (!androidS) {
switchTask?.invoke()
}
super.onDestroy()
}

private fun syncTheme(isNight: Boolean) {
binding.apply {
val bgWindow = if (isNight) {
R.color.bgWindowNight
} else {
R.color.bgWindow
}
val bgColor = if (isNight) {
R.color.bgWhiteNight
} else {
R.color.bgWhite
}
val iconColor = if (isNight) {
R.color.colorIconNight
} else {
R.color.colorIcon
}
val textPrimary = if (isNight) {
R.color.textPrimaryNight
} else {
R.color.textPrimary
}
val textMinor = if (isNight) {
R.color.textMinorNight
} else {
R.color.textMinor
}
root.setBackgroundResource(bgWindow)
titleView.root.setBackgroundResource(bgColor)
titleView.leftIb.setColorFilter(requireContext().getColor(iconColor))
titleView.titleTv.textColorResource = textPrimary
nightModeRl.setBackgroundResource(bgColor)
languageRl.setBackgroundResource(bgColor)
currencyRl.setBackgroundResource(bgColor)
nightModeTv.textColorResource = textPrimary
languageTv.textColorResource = textPrimary
languageDescTv.textColorResource = textMinor
currencyTv.textColorResource = textPrimary
currentTv.textColorResource = textMinor

Timber.e("isNight $isNight")
val window = requireActivity().window
SystemUIManager.lightUI(window, !isNight)
SystemUIManager.setSystemUiColor(window, requireContext().getColor(bgColor))
}
}

private fun showLanguageAlert() {
val choice = resources.getStringArray(R.array.language_names)
choice[0] = getString(R.string.Follow_system)
Expand Down Expand Up @@ -152,6 +252,33 @@ class AppearanceFragment : BaseFragment(R.layout.fragment_appearance) {
}
.show()
}

private fun getViewCoordinates(view: View): Coordinate {
return Coordinate(
getRelativeLeft(view) + view.width / 2,
getRelativeTop(view) + view.height / 2
)
}

private fun getRelativeLeft(myView: View): Int {
return if ((myView.parent as View).id == ThemeActivity.ROOT_ID) {
myView.left
} else {
myView.left + getRelativeLeft(
myView.parent as View
)
}
}

private fun getRelativeTop(myView: View): Int {
return if ((myView.parent as View).id == ThemeActivity.ROOT_ID) {
myView.top
} else {
myView.top + getRelativeTop(
myView.parent as View
)
}
}
}

fun getLanguagePos() = when (getLanguage()) {
Expand Down
36 changes: 19 additions & 17 deletions app/src/main/java/one/mixin/android/ui/setting/SettingActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import one.mixin.android.api.response.AuthorizationResponse
import one.mixin.android.databinding.ActivityContactBinding
import one.mixin.android.extension.addFragment
import one.mixin.android.extension.replaceFragment
import one.mixin.android.ui.common.BlazeBaseActivity
import one.mixin.android.util.viewBinding
import one.mixin.android.vo.App
import one.mixin.android.widget.theme.ThemeActivity

@AndroidEntryPoint
class SettingActivity : BlazeBaseActivity() {
class SettingActivity : ThemeActivity() {
companion object {
const val FROM_NOTIFICATION = "notification"
const val EXTRA_SHOW_PIN_SETTING = "extra_show_pin_setting"
Expand Down Expand Up @@ -57,21 +57,23 @@ class SettingActivity : BlazeBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
if (intent.getBooleanExtra(EXTRA_SHOW_PIN_SETTING, false)) {
replaceFragment(PinSettingFragment.newInstance(), R.id.container, PinSettingFragment.TAG)
} else if (intent.getBooleanExtra(EXTRA_EMERGENCY_CONTACT, false)) {
replaceFragment(EmergencyContactFragment.newInstance(), R.id.container, EmergencyContactFragment.TAG)
} else if (intent.getBooleanExtra(EXTRA_SHOW_PERMISSION_LIST, false)) {
val app = requireNotNull(intent.getParcelableExtra<App>(EXTRA_APP))
val auth = requireNotNull(intent.getParcelableExtra<AuthorizationResponse>(EXTRA_AUTH))
replaceFragment(PermissionListFragment.newInstance(app, auth), R.id.container, PermissionListFragment.TAG)
} else if (intent.getBooleanExtra(EXTRA_SHOW_COMPOSE, false)) {
replaceFragment(SettingComposeFragment.newInstance(), R.id.container, SettingComposeFragment.TAG)
} else {
val fragment = SettingFragment.newInstance()
replaceFragment(fragment, R.id.container, SettingFragment.TAG)
if (intent.getBooleanExtra(FROM_NOTIFICATION, false)) {
addFragment(fragment, BackUpFragment.newInstance(), BackUpFragment.TAG)
if (savedInstanceState == null) {
if (intent.getBooleanExtra(EXTRA_SHOW_PIN_SETTING, false)) {
replaceFragment(PinSettingFragment.newInstance(), R.id.container, PinSettingFragment.TAG)
} else if (intent.getBooleanExtra(EXTRA_EMERGENCY_CONTACT, false)) {
replaceFragment(EmergencyContactFragment.newInstance(), R.id.container, EmergencyContactFragment.TAG)
} else if (intent.getBooleanExtra(EXTRA_SHOW_PERMISSION_LIST, false)) {
val app = requireNotNull(intent.getParcelableExtra<App>(EXTRA_APP))
val auth = requireNotNull(intent.getParcelableExtra<AuthorizationResponse>(EXTRA_AUTH))
replaceFragment(PermissionListFragment.newInstance(app, auth), R.id.container, PermissionListFragment.TAG)
} else if (intent.getBooleanExtra(EXTRA_SHOW_COMPOSE, false)) {
replaceFragment(SettingComposeFragment.newInstance(), R.id.container, SettingComposeFragment.TAG)
} else {
val fragment = SettingFragment.newInstance()
replaceFragment(fragment, R.id.container, SettingFragment.TAG)
if (intent.getBooleanExtra(FROM_NOTIFICATION, false)) {
addFragment(fragment, BackUpFragment.newInstance(), BackUpFragment.TAG)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import one.mixin.android.ui.setting.ui.theme.MixinAppTheme
import one.mixin.android.util.TimeCache
import one.mixin.android.util.isFollowSystem
import one.mixin.android.vo.Fiats
import java.util.*
import java.util.Locale

@Composable
fun AppearancePage() {
Expand Down Expand Up @@ -88,7 +88,7 @@ private fun ThemeItem() {
val id = preference.getInt(
Constants.Theme.THEME_CURRENT_ID,
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Constants.Theme.THEME_DEFAULT_ID
Constants.Theme.THEME_LIGHT_ID
} else {
Constants.Theme.THEME_AUTO_ID
}
Expand All @@ -114,7 +114,7 @@ private fun ThemeItem() {
preference.putInt(Constants.Theme.THEME_CURRENT_ID, index)
AppCompatDelegate.setDefaultNightMode(
when (index) {
Constants.Theme.THEME_DEFAULT_ID -> AppCompatDelegate.MODE_NIGHT_NO
Constants.Theme.THEME_LIGHT_ID -> AppCompatDelegate.MODE_NIGHT_NO
Constants.Theme.THEME_NIGHT_ID -> AppCompatDelegate.MODE_NIGHT_YES
Constants.Theme.THEME_AUTO_ID -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
else -> AppCompatDelegate.MODE_NIGHT_NO
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/one/mixin/android/widget/TitleView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class TitleView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
private val binding: ViewTitleBinding =
ViewTitleBinding.inflate(LayoutInflater.from(context), this, true)

val root = binding.root
val titleTv = binding.titleTv
val leftIb = binding.leftIb
val rightIb = binding.rightIb
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package one.mixin.android.widget.theme

data class Coordinate(var x: Int, var y: Int)
Loading