diff --git a/app/core/src/main/java/com/fsck/k9/K9.kt b/app/core/src/main/java/com/fsck/k9/K9.kt index f5474c599..ed8407dd8 100644 --- a/app/core/src/main/java/com/fsck/k9/K9.kt +++ b/app/core/src/main/java/com/fsck/k9/K9.kt @@ -326,10 +326,6 @@ object K9 : KoinComponent { val k9MessageViewTheme: Theme get() = if (k9MessageViewThemeSetting == Theme.USE_GLOBAL) k9Theme else k9MessageViewThemeSetting - @JvmStatic - val k9ComposerTheme: Theme - get() = if (k9ComposerThemeSetting == Theme.USE_GLOBAL) k9Theme else k9ComposerThemeSetting - val isQuietTime: Boolean get() { if (!isQuietTimeEnabled) { diff --git a/app/ui/src/main/java/com/fsck/k9/activity/K9Activity.java b/app/ui/src/main/java/com/fsck/k9/activity/K9Activity.java index 1d9db34a2..93494988e 100644 --- a/app/ui/src/main/java/com/fsck/k9/activity/K9Activity.java +++ b/app/ui/src/main/java/com/fsck/k9/activity/K9Activity.java @@ -16,6 +16,7 @@ import android.view.View; import com.fsck.k9.activity.K9ActivityCommon.K9ActivityMagic; import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener; import com.fsck.k9.ui.R; +import com.fsck.k9.ui.ThemeManager; import com.fsck.k9.ui.permissions.PermissionRationaleDialogFragment; import timber.log.Timber; @@ -28,6 +29,9 @@ public abstract class K9Activity extends AppCompatActivity implements K9Activity private final K9ActivityCommon base = new K9ActivityCommon(this, ThemeType.DEFAULT); + public ThemeManager getThemeManager() { + return base.getThemeManager(); + } @Override public void onCreate(Bundle savedInstanceState) { diff --git a/app/ui/src/main/java/com/fsck/k9/activity/K9ActivityCommon.kt b/app/ui/src/main/java/com/fsck/k9/activity/K9ActivityCommon.kt index 3da7073d8..9c2cf3604 100644 --- a/app/ui/src/main/java/com/fsck/k9/activity/K9ActivityCommon.kt +++ b/app/ui/src/main/java/com/fsck/k9/activity/K9ActivityCommon.kt @@ -1,18 +1,17 @@ package com.fsck.k9.activity -import java.util.Locale - import android.app.Activity import android.content.res.Resources import android.text.TextUtils import android.view.GestureDetector import android.view.MotionEvent - import com.fsck.k9.K9 -import com.fsck.k9.K9.Theme import com.fsck.k9.activity.misc.SwipeGestureDetector import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener -import com.fsck.k9.ui.R +import com.fsck.k9.ui.ThemeManager +import org.koin.standalone.KoinComponent +import org.koin.standalone.inject +import java.util.Locale /** @@ -27,6 +26,9 @@ class K9ActivityCommon( ) { private var gestureDetector: GestureDetector? = null + val themeManager = Companion.themeManager + + /** * Call this before calling `super.onCreate(Bundle)`. */ @@ -34,9 +36,9 @@ class K9ActivityCommon( setLanguage(K9.k9Language) val theme = when (themeType) { - ThemeType.DEFAULT -> k9ThemeResourceId - ThemeType.ACTION_BAR -> k9ActionBarThemeResourceId - ThemeType.DIALOG -> translucentDialogThemeResourceId + ThemeType.DEFAULT -> themeManager.appThemeResourceId + ThemeType.ACTION_BAR -> themeManager.appActionBarThemeResourceId + ThemeType.DIALOG -> themeManager.translucentDialogThemeResourceId } activity.setTheme(theme) } @@ -74,28 +76,8 @@ class K9ActivityCommon( } - companion object { - @JvmStatic - fun getK9ThemeResourceId(themeId: Theme): Int { - return if (themeId === Theme.LIGHT) R.style.Theme_K9_Light else R.style.Theme_K9_Dark - } - - @JvmStatic - val k9ActionBarThemeResourceId: Int - get() = if (k9ThemeResourceId == R.style.Theme_K9_Light) - R.style.Theme_K9_Light_ActionBar - else - R.style.Theme_K9_Dark_ActionBar - - @JvmStatic - val k9ThemeResourceId: Int - get() = getK9ThemeResourceId(K9.k9Theme) - - private val translucentDialogThemeResourceId: Int - get() = if (k9ThemeResourceId == R.style.Theme_K9_Light) - R.style.Theme_K9_Dialog_Translucent_Light - else - R.style.Theme_K9_Dialog_Translucent_Dark + companion object : KoinComponent { + private val themeManager: ThemeManager by inject() } /** diff --git a/app/ui/src/main/java/com/fsck/k9/activity/MessageCompose.java b/app/ui/src/main/java/com/fsck/k9/activity/MessageCompose.java index 59f288652..cf45e1123 100644 --- a/app/ui/src/main/java/com/fsck/k9/activity/MessageCompose.java +++ b/app/ui/src/main/java/com/fsck/k9/activity/MessageCompose.java @@ -100,6 +100,7 @@ import com.fsck.k9.message.SimpleMessageFormat; import com.fsck.k9.search.LocalSearch; import com.fsck.k9.ui.EolConvertingEditText; import com.fsck.k9.ui.R; +import com.fsck.k9.ui.ThemeManager; import com.fsck.k9.ui.compose.QuotedMessageMvpView; import com.fsck.k9.ui.compose.QuotedMessagePresenter; import org.openintents.openpgp.OpenPgpApiManager; @@ -232,10 +233,11 @@ public class MessageCompose extends K9Activity implements OnClickListener, } requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - if (K9.getK9ComposerThemeSetting() != K9.Theme.USE_GLOBAL) { + ThemeManager themeManager = getThemeManager(); + if (themeManager.getMessageComposeTheme() != themeManager.getAppTheme()) { // theme the whole content according to the theme (except the action bar) - ContextThemeWrapper themeContext = new ContextThemeWrapper(this, - K9ActivityCommon.getK9ThemeResourceId(K9.getK9ComposerTheme())); + int messageComposeThemeResourceId = themeManager.getMessageComposeThemeResourceId(); + ContextThemeWrapper themeContext = new ContextThemeWrapper(this, messageComposeThemeResourceId); @SuppressLint("InflateParams") // this is the top level activity element, it has no root View v = LayoutInflater.from(themeContext).inflate(R.layout.message_compose, null); TypedValue outValue = new TypedValue(); @@ -1127,10 +1129,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, }) .create(); case DIALOG_CHOOSE_IDENTITY: - Context context = new ContextThemeWrapper(this, - (K9.getK9Theme() == K9.Theme.LIGHT) ? - R.style.Theme_K9_Dialog_Light : - R.style.Theme_K9_Dialog_Dark); + int dialogThemeResourceId = getThemeManager().getDialogThemeResourceId(); + Context context = new ContextThemeWrapper(this, dialogThemeResourceId); Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.send_as); final IdentityAdapter adapter = new IdentityAdapter(context); diff --git a/app/ui/src/main/java/com/fsck/k9/activity/MessageList.java b/app/ui/src/main/java/com/fsck/k9/activity/MessageList.java index 8ea721776..02095f820 100644 --- a/app/ui/src/main/java/com/fsck/k9/activity/MessageList.java +++ b/app/ui/src/main/java/com/fsck/k9/activity/MessageList.java @@ -47,7 +47,6 @@ import com.fsck.k9.helper.ParcelableUtil; import com.fsck.k9.mailstore.SearchStatusManager; import com.fsck.k9.mailstore.StorageManager; import com.fsck.k9.notification.NotificationChannelManager; -import com.fsck.k9.preferences.StorageEditor; import com.fsck.k9.search.LocalSearch; import com.fsck.k9.search.SearchAccount; import com.fsck.k9.search.SearchSpecification; @@ -56,6 +55,7 @@ import com.fsck.k9.search.SearchSpecification.SearchCondition; import com.fsck.k9.search.SearchSpecification.SearchField; import com.fsck.k9.ui.K9Drawer; import com.fsck.k9.ui.R; +import com.fsck.k9.ui.Theme; import com.fsck.k9.ui.messageview.MessageViewFragment; import com.fsck.k9.ui.messageview.MessageViewFragment.MessageViewFragmentListener; import com.fsck.k9.ui.settings.SettingsActivity; @@ -1075,7 +1075,7 @@ public class MessageList extends K9Activity implements MessageListFragmentListen toggleTheme.setVisible(false); } else { // Set title of menu item to switch to dark/light theme - if (K9.getK9MessageViewTheme() == K9.Theme.DARK) { + if (getThemeManager().getMessageViewTheme() == Theme.DARK) { toggleTheme.setTitle(R.string.message_view_theme_action_light); } else { toggleTheme.setTitle(R.string.message_view_theme_action_dark); @@ -1564,21 +1564,7 @@ public class MessageList extends K9Activity implements MessageListFragmentListen } private void onToggleTheme() { - if (K9.getK9MessageViewTheme() == K9.Theme.DARK) { - K9.setK9MessageViewThemeSetting(K9.Theme.LIGHT); - } else { - K9.setK9MessageViewThemeSetting(K9.Theme.DARK); - } - - new Thread(new Runnable() { - @Override - public void run() { - StorageEditor editor = preferences.createStorageEditor(); - K9.save(editor); - editor.commit(); - } - }).start(); - + getThemeManager().toggleMessageViewTheme(); recreate(); } diff --git a/app/ui/src/main/java/com/fsck/k9/contacts/ContactLetterBitmapConfig.kt b/app/ui/src/main/java/com/fsck/k9/contacts/ContactLetterBitmapConfig.kt index dcabba556..1255c5b36 100644 --- a/app/ui/src/main/java/com/fsck/k9/contacts/ContactLetterBitmapConfig.kt +++ b/app/ui/src/main/java/com/fsck/k9/contacts/ContactLetterBitmapConfig.kt @@ -4,17 +4,17 @@ import android.content.Context import android.util.TypedValue import android.view.ContextThemeWrapper import com.fsck.k9.K9 -import com.fsck.k9.activity.K9ActivityCommon import com.fsck.k9.ui.R +import com.fsck.k9.ui.ThemeManager -class ContactLetterBitmapConfig(context: Context) { +class ContactLetterBitmapConfig(context: Context, themeManager: ThemeManager) { val hasDefaultBackgroundColor: Boolean = !K9.isColorizeMissingContactPictures val defaultBackgroundColor: Int init { defaultBackgroundColor = if (hasDefaultBackgroundColor) { val outValue = TypedValue() - val themedContext = ContextThemeWrapper(context, K9ActivityCommon.k9ThemeResourceId) + val themedContext = ContextThemeWrapper(context, themeManager.appThemeResourceId) themedContext.theme.resolveAttribute(R.attr.contactPictureFallbackDefaultBackgroundColor, outValue, true) outValue.data } else { diff --git a/app/ui/src/main/java/com/fsck/k9/contacts/KoinModule.kt b/app/ui/src/main/java/com/fsck/k9/contacts/KoinModule.kt index e34c6aa2b..306e0360c 100644 --- a/app/ui/src/main/java/com/fsck/k9/contacts/KoinModule.kt +++ b/app/ui/src/main/java/com/fsck/k9/contacts/KoinModule.kt @@ -4,7 +4,7 @@ import org.koin.dsl.module.applicationContext val contactsModule = applicationContext { bean { ContactLetterExtractor() } - factory { ContactLetterBitmapConfig(get()) } + factory { ContactLetterBitmapConfig(get(), get()) } factory { ContactLetterBitmapCreator(get(), get()) } factory { ContactPictureLoader(get(), get()) } } diff --git a/app/ui/src/main/java/com/fsck/k9/ui/KoinModule.kt b/app/ui/src/main/java/com/fsck/k9/ui/KoinModule.kt index 87a8cf350..730215e49 100644 --- a/app/ui/src/main/java/com/fsck/k9/ui/KoinModule.kt +++ b/app/ui/src/main/java/com/fsck/k9/ui/KoinModule.kt @@ -7,4 +7,5 @@ import org.koin.dsl.module.applicationContext val uiModule = applicationContext { bean { FolderNameFormatter(get()) } bean { HtmlToSpanned() } + bean { ThemeManager() } } diff --git a/app/ui/src/main/java/com/fsck/k9/ui/ThemeManager.kt b/app/ui/src/main/java/com/fsck/k9/ui/ThemeManager.kt new file mode 100644 index 000000000..1dfa8fb89 --- /dev/null +++ b/app/ui/src/main/java/com/fsck/k9/ui/ThemeManager.kt @@ -0,0 +1,78 @@ +package com.fsck.k9.ui + +import androidx.annotation.StyleRes +import com.fsck.k9.K9 + +class ThemeManager { + val appTheme: Theme + get() = when (K9.k9Theme) { + K9.Theme.LIGHT -> Theme.LIGHT + K9.Theme.DARK -> Theme.DARK + K9.Theme.USE_GLOBAL -> error("App theme must be either LIGHT or DARK") + } + + val messageViewTheme: Theme + get() = resolveTheme(K9.k9MessageViewThemeSetting) + + val messageComposeTheme: Theme + get() = resolveTheme(K9.k9ComposerThemeSetting) + + @get:StyleRes + val appThemeResourceId: Int + get() = getThemeResourceId(appTheme) + + @get:StyleRes + val appActionBarThemeResourceId: Int + get() = when (appTheme) { + Theme.LIGHT -> R.style.Theme_K9_Light_ActionBar + Theme.DARK -> R.style.Theme_K9_Dark_ActionBar + } + + @get:StyleRes + val messageViewThemeResourceId: Int + get() = getThemeResourceId(messageViewTheme) + + @get:StyleRes + val messageComposeThemeResourceId: Int + get() = getThemeResourceId(messageComposeTheme) + + @get:StyleRes + val dialogThemeResourceId: Int + get() = when (appTheme) { + Theme.LIGHT -> R.style.Theme_K9_Dialog_Light + Theme.DARK -> R.style.Theme_K9_Dialog_Dark + } + + @get:StyleRes + val translucentDialogThemeResourceId: Int + get() = when (appTheme) { + Theme.LIGHT -> R.style.Theme_K9_Dialog_Translucent_Light + Theme.DARK -> R.style.Theme_K9_Dialog_Translucent_Dark + } + + fun toggleMessageViewTheme() { + if (messageViewTheme === Theme.DARK) { + K9.k9MessageViewThemeSetting = K9.Theme.LIGHT + } else { + K9.k9MessageViewThemeSetting = K9.Theme.DARK + } + + K9.saveSettingsAsync() + } + + private fun getThemeResourceId(theme: Theme): Int = when (theme) { + Theme.LIGHT -> R.style.Theme_K9_Light + Theme.DARK -> R.style.Theme_K9_Dark + } + + private fun resolveTheme(theme: K9.Theme): Theme = when (theme) { + K9.Theme.LIGHT -> Theme.LIGHT + K9.Theme.DARK -> Theme.DARK + K9.Theme.USE_GLOBAL -> appTheme + } +} + +enum class Theme { + LIGHT, + DARK +} diff --git a/app/ui/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java b/app/ui/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java index 4b869a8b4..332853491 100644 --- a/app/ui/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java +++ b/app/ui/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java @@ -30,10 +30,10 @@ import android.view.inputmethod.InputMethodManager; import android.widget.Toast; import com.fsck.k9.Account; +import com.fsck.k9.DI; import com.fsck.k9.K9; import com.fsck.k9.Preferences; import com.fsck.k9.activity.ChooseFolder; -import com.fsck.k9.activity.K9ActivityCommon; import com.fsck.k9.activity.MessageLoaderHelper; import com.fsck.k9.activity.MessageLoaderHelper.MessageLoaderCallbacks; import com.fsck.k9.controller.MessageReference; @@ -46,6 +46,7 @@ import com.fsck.k9.mailstore.AttachmentViewInfo; import com.fsck.k9.mailstore.LocalMessage; import com.fsck.k9.mailstore.MessageViewInfo; import com.fsck.k9.ui.R; +import com.fsck.k9.ui.ThemeManager; import com.fsck.k9.ui.messageview.CryptoInfoDialog.OnClickShowCryptoKeyListener; import com.fsck.k9.ui.messageview.MessageCryptoPresenter.MessageCryptoMvpView; import com.fsck.k9.ui.settings.account.AccountSettingsActivity; @@ -77,6 +78,8 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF return fragment; } + private final ThemeManager themeManager = DI.get(ThemeManager.class); + private MessageTopView mMessageView; private Account mAccount; @@ -159,10 +162,9 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - Context context = new ContextThemeWrapper(inflater.getContext(), - K9ActivityCommon.getK9ThemeResourceId(K9.getK9MessageViewTheme())); + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + int messageViewThemeResourceId = themeManager.getMessageViewThemeResourceId(); + Context context = new ContextThemeWrapper(inflater.getContext(), messageViewThemeResourceId); LayoutInflater layoutInflater = LayoutInflater.from(context); View view = layoutInflater.inflate(R.layout.message, container, false);