diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsAppearanceFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsAppearanceFragment.java new file mode 100644 index 000000000..3fc28515f --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsAppearanceFragment.java @@ -0,0 +1,61 @@ +package org.joinmastodon.android.fragments.settings; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.os.Build; +import android.view.Gravity; +import android.view.View; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.PopupMenu; + +import androidx.recyclerview.widget.RecyclerView; + +import org.joinmastodon.android.GlobalUserPreferences; +import org.joinmastodon.android.MastodonApp; +import org.joinmastodon.android.R; +import org.joinmastodon.android.ui.utils.UiUtils; + +import java.util.ArrayList; + +public class SettingsAppearanceFragment extends SettingsBaseFragment { + @Override + public void addItems(ArrayList items) { + items.add(themeItem SettingsBaseFragment.ThemeItem()); + items.add(new SettingsFragment.ButtonItem(R.string.sk_settings_color_palette, R.drawable.ic_fluent_color_24_regular, b -> { + PopupMenu popupMenu = new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL); + popupMenu.inflate(R.menu.color_palettes); + popupMenu.getMenu().findItem(R.id.m3_color).setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S); + popupMenu.setOnMenuItemClickListener(SettingsBaseFragment.this::onColorPreferenceClick); + b.setOnTouchListener(popupMenu.getDragToOpenListener()); + b.setOnClickListener(v -> popupMenu.show()); + b.setText(switch (GlobalUserPreferences.color) { + case MATERIAL3 -> R.string.sk_color_palette_material3; + case PINK -> R.string.sk_color_palette_pink; + case PURPLE -> R.string.sk_color_palette_purple; + case GREEN -> R.string.sk_color_palette_green; + case BLUE -> R.string.sk_color_palette_blue; + case BROWN -> R.string.sk_color_palette_brown; + case RED -> R.string.sk_color_palette_red; + case YELLOW -> R.string.sk_color_palette_yellow; + case NORD -> R.string.mo_color_palette_nord; + }); + })); + items.add(new SettingsBaseFragment.SwitchItem(R.string.theme_true_black, R.drawable.ic_fluent_dark_theme_24_regular, GlobalUserPreferences.trueBlackTheme, this::onTrueBlackThemeChanged)); + items.add(new SettingsBaseFragment.SwitchItem(R.string.sk_disable_marquee, R.drawable.ic_fluent_text_more_24_regular, GlobalUserPreferences.disableMarquee, i -> { + GlobalUserPreferences.disableMarquee = i.checked; + GlobalUserPreferences.save(); + needAppRestart = true; + })); + items.add(new SettingsBaseFragment.SwitchItem(R.string.sk_settings_uniform_icon_for_notifications, R.drawable.ic_ntf_logo, GlobalUserPreferences.uniformNotificationIcon, i -> { + GlobalUserPreferences.uniformNotificationIcon = i.checked; + GlobalUserPreferences.save(); + })); + items.add(new SettingsBaseFragment.SwitchItem(R.string.sk_settings_reduce_motion, R.drawable.ic_fluent_star_emphasis_24_regular, GlobalUserPreferences.reduceMotion, i -> { + GlobalUserPreferences.reduceMotion = i.checked; + GlobalUserPreferences.save(); + needAppRestart = true; + })); + } +} + diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBaseFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBaseFragment.java index 93f7429b7..d11ef067d 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBaseFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBaseFragment.java @@ -10,6 +10,7 @@ import android.os.Bundle; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; @@ -35,6 +36,7 @@ import org.joinmastodon.android.DomainManager; import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.MastodonApp; import org.joinmastodon.android.R; +import org.joinmastodon.android.api.PushSubscriptionManager; import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.fragments.DomainDisplay; @@ -54,17 +56,21 @@ import me.grishka.appkit.views.UsableRecyclerView; public abstract class SettingsBaseFragment extends MastodonToolbarFragment implements DomainDisplay { protected View view; - private UsableRecyclerView list; + protected UsableRecyclerView list; - private ImageView themeTransitionWindowView; + protected ImageView themeTransitionWindowView; - private SettingsBaseFragment.NotificationPolicyItem notificationPolicyItem; + protected ThemeItem themeItem; - private PushSubscription pushSubscription; - private ArrayList items=new ArrayList<>(); - private String accountID; + protected boolean needAppRestart; - private boolean needUpdateNotificationSettings; + protected SettingsBaseFragment.NotificationPolicyItem notificationPolicyItem; + + protected PushSubscription pushSubscription; + protected ArrayList items=new ArrayList<>(); + protected String accountID; + + protected boolean needUpdateNotificationSettings; public abstract void addItems(ArrayList items); @@ -142,7 +148,7 @@ public abstract class SettingsBaseFragment extends MastodonToolbarFragment imple protected class SwitchItem extends Item{ private String text; private int icon; - private boolean checked; + boolean checked; private Consumer onChanged; private boolean enabled=true; @@ -389,13 +395,35 @@ public abstract class SettingsBaseFragment extends MastodonToolbarFragment imple } } - private void onThemePreferenceClick(GlobalUserPreferences.ThemePreference theme){ + protected boolean onColorPreferenceClick(MenuItem item){ + GlobalUserPreferences.ColorPreference pref = null; + int id = item.getItemId(); + + if (id == R.id.m3_color) pref = GlobalUserPreferences.ColorPreference.MATERIAL3; + else if (id == R.id.pink_color) pref = GlobalUserPreferences.ColorPreference.PINK; + else if (id == R.id.purple_color) pref = GlobalUserPreferences.ColorPreference.PURPLE; + else if (id == R.id.green_color) pref = GlobalUserPreferences.ColorPreference.GREEN; + else if (id == R.id.blue_color) pref = GlobalUserPreferences.ColorPreference.BLUE; + else if (id == R.id.brown_color) pref = GlobalUserPreferences.ColorPreference.BROWN; + else if (id == R.id.red_color) pref = GlobalUserPreferences.ColorPreference.RED; + else if (id == R.id.yellow_color) pref = GlobalUserPreferences.ColorPreference.YELLOW; + else if (id == R.id.nord_color) pref = GlobalUserPreferences.ColorPreference.NORD; + + if (pref == null) return false; + + GlobalUserPreferences.color=pref; + GlobalUserPreferences.save(); + restartActivityToApplyNewTheme(); + return true; + } + + protected void onThemePreferenceClick(GlobalUserPreferences.ThemePreference theme){ GlobalUserPreferences.theme=theme; GlobalUserPreferences.save(); restartActivityToApplyNewTheme(); } - private void restartActivityToApplyNewTheme(){ + protected void restartActivityToApplyNewTheme(){ // Calling activity.recreate() causes a black screen for like half a second. // So, let's take a screenshot and overlay it on top to create the illusion of a smoother transition. // As a bonus, we can fade it out to make it even smoother. @@ -418,6 +446,32 @@ public abstract class SettingsBaseFragment extends MastodonToolbarFragment imple getActivity().recreate(); } + @Override + public void onDestroy(){ + super.onDestroy(); + if(needUpdateNotificationSettings && PushSubscriptionManager.arePushNotificationsAvailable()){ + AccountSessionManager.getInstance().getAccount(accountID).getPushSubscriptionManager().updatePushSettings(pushSubscription); + } + if(needAppRestart) UiUtils.restartApp(); + } + + + protected void onTrueBlackThemeChanged(SettingsBaseFragment.SwitchItem item){ + GlobalUserPreferences.trueBlackTheme=item.checked; + GlobalUserPreferences.save(); + + RecyclerView.ViewHolder themeHolder=list.findViewHolderForAdapterPosition(items.indexOf(themeItem)); + if(themeHolder!=null){ + ((SettingsBaseFragment.ThemeViewHolder)themeHolder).bindSubitems(); + }else{ + list.getAdapter().notifyItemChanged(items.indexOf(themeItem)); + } + + if(UiUtils.isDarkTheme()){ + restartActivityToApplyNewTheme(); + } + } + private class NotificationPolicyViewHolder extends BindableViewHolder{ private final Button button; private final PopupMenu popupMenu; @@ -492,7 +546,7 @@ public abstract class SettingsBaseFragment extends MastodonToolbarFragment imple needUpdateNotificationSettings=true; } - private void onNotificationsChanged(PushNotification.Type type, boolean enabled){ + protected void onNotificationsChanged(PushNotification.Type type, boolean enabled){ PushSubscription subscription=getPushSubscription(); switch(type){ case FAVORITE -> subscription.alerts.favourite=enabled; @@ -506,7 +560,7 @@ public abstract class SettingsBaseFragment extends MastodonToolbarFragment imple needUpdateNotificationSettings=true; } - private PushSubscription getPushSubscription(){ + protected PushSubscription getPushSubscription(){ if(pushSubscription!=null) return pushSubscription; AccountSession session=AccountSessionManager.getInstance().getAccount(accountID); @@ -557,7 +611,7 @@ public abstract class SettingsBaseFragment extends MastodonToolbarFragment imple } } - private class ThemeViewHolder extends BindableViewHolder{ + class ThemeViewHolder extends BindableViewHolder{ private ThemeViewHolder.SubitemHolder autoHolder, lightHolder, darkHolder; public ThemeViewHolder(){ @@ -637,7 +691,7 @@ public abstract class SettingsBaseFragment extends MastodonToolbarFragment imple } } - private class ButtonViewHolder extends BindableViewHolder{ + protected class ButtonViewHolder extends BindableViewHolder{ private final Button button; private final ImageView icon; private final TextView text;