diff --git a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java index 876f5bbeb..258b5251b 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java +++ b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java @@ -3,6 +3,7 @@ package org.joinmastodon.android; import android.content.Context; import android.content.SharedPreferences; +import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.model.Account; @@ -12,6 +13,10 @@ public class GlobalUserPreferences{ public static boolean altTextReminders, confirmUnfollow, confirmBoost, confirmDeletePost; public static ThemePreference theme=ThemePreference.AUTO; public static boolean useDynamicColors; + public static boolean showInteractionCounts; + public static boolean customEmojiInNames; + public static boolean showCWs; + public static boolean hideSensitiveMedia; private static SharedPreferences getPrefs(){ return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE); @@ -31,6 +36,19 @@ public class GlobalUserPreferences{ confirmDeletePost=prefs.getBoolean("confirmDeletePost", true); theme=ThemePreference.values()[prefs.getInt("theme", 0)]; useDynamicColors=prefs.getBoolean("useDynamicColors", true); + if(!prefs.getBoolean("perAccountMigrationDone", false)){ + AccountSession account=AccountSessionManager.getInstance().getLastActiveAccount(); + if(account!=null){ + SharedPreferences accPrefs=account.getRawLocalPreferences(); + showInteractionCounts=accPrefs.getBoolean("interactionCounts", true); + customEmojiInNames=accPrefs.getBoolean("emojiInNames", true); + showCWs=accPrefs.getBoolean("showCWs", true); + hideSensitiveMedia=accPrefs.getBoolean("hideSensitive", true); + save(); + } + // Also applies to new app installs + prefs.edit().putBoolean("perAccountMigrationDone", true).apply(); + } } public static void save(){ @@ -43,6 +61,10 @@ public class GlobalUserPreferences{ .putBoolean("confirmBoost", confirmBoost) .putBoolean("confirmDeletePost", confirmDeletePost) .putBoolean("useDynamicColors", useDynamicColors) + .putBoolean("interactionCounts", showInteractionCounts) + .putBoolean("emojiInNames", customEmojiInNames) + .putBoolean("showCWs", showCWs) + .putBoolean("hideSensitive", hideSensitiveMedia) .apply(); } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountLocalPreferences.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountLocalPreferences.java index a1eb474f1..7f0808833 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountLocalPreferences.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountLocalPreferences.java @@ -5,18 +5,10 @@ import android.content.SharedPreferences; public class AccountLocalPreferences{ private final SharedPreferences prefs; - public boolean showInteractionCounts; - public boolean customEmojiInNames; - public boolean showCWs; - public boolean hideSensitiveMedia; public boolean serverSideFiltersSupported; public AccountLocalPreferences(SharedPreferences prefs){ this.prefs=prefs; - showInteractionCounts=prefs.getBoolean("interactionCounts", true); - customEmojiInNames=prefs.getBoolean("emojiInNames", true); - showCWs=prefs.getBoolean("showCWs", true); - hideSensitiveMedia=prefs.getBoolean("hideSensitive", true); serverSideFiltersSupported=prefs.getBoolean("serverSideFilters", false); } @@ -30,10 +22,6 @@ public class AccountLocalPreferences{ public void save(){ prefs.edit() - .putBoolean("interactionCounts", showInteractionCounts) - .putBoolean("emojiInNames", customEmojiInNames) - .putBoolean("showCWs", showCWs) - .putBoolean("hideSensitive", hideSensitiveMedia) .putBoolean("serverSideFilters", serverSideFiltersSupported) .apply(); } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java index 7f4fe8ff6..f622ab5bc 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java @@ -500,7 +500,7 @@ public abstract class BaseStatusListFragment exten int itemCount=spoilerItem.contentItems.size(); displayItems.addAll(index+1, spoilerItem.contentItems); if(spoilerItem.spoilerType==Status.SpoilerType.FILTER && spoilerItem.contentItems.get(0) instanceof SpoilerStatusDisplayItem nestedSpoiler - && nestedSpoiler.spoilerType==Status.SpoilerType.CONTENT_WARNING && !AccountSessionManager.get(accountID).getLocalPreferences().showCWs){ + && nestedSpoiler.spoilerType==Status.SpoilerType.CONTENT_WARNING && !GlobalUserPreferences.showCWs){ status.revealedSpoilers.add(Status.SpoilerType.CONTENT_WARNING); displayItems.addAll(index+1+itemCount, nestedSpoiler.contentItems); itemCount+=nestedSpoiler.contentItems.size(); diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java index ef44a95f8..6be4565d2 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java @@ -560,7 +560,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop, ViewImageLoader.loadWithoutAnimation(avatar, avatar.getDrawable(), new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic, V.dp(100), V.dp(100))); ViewImageLoader.loadWithoutAnimation(cover, cover.getDrawable(), new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.header : account.headerStatic, 1000, 1000)); SpannableStringBuilder ssb=new SpannableStringBuilder(account.displayName); - if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames) + if(GlobalUserPreferences.customEmojiInNames) HtmlParser.parseCustomEmoji(ssb, account.emojis); name.setText(ssb); setTitle(ssb); diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java index 9a8d06453..86b366a58 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java @@ -68,7 +68,7 @@ public class ThreadFragment extends StatusListFragment implements AssistContentP knownAccounts.put(inReplyToAccount.id, inReplyToAccount); data.add(mainStatus); onAppendItems(Collections.singletonList(mainStatus)); - if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames) + if(GlobalUserPreferences.customEmojiInNames) setTitle(HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.displayName), mainStatus.account.emojis)); else setTitle(getString(R.string.post_from_user, mainStatus.account.displayName)); diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsAccountFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsAccountFragment.java new file mode 100644 index 000000000..8b880f755 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsAccountFragment.java @@ -0,0 +1,239 @@ +package org.joinmastodon.android.fragments.settings; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import org.joinmastodon.android.BuildConfig; +import org.joinmastodon.android.MainActivity; +import org.joinmastodon.android.R; +import org.joinmastodon.android.api.requests.catalog.GetDonationCampaigns; +import org.joinmastodon.android.api.session.AccountSession; +import org.joinmastodon.android.api.session.AccountSessionManager; +import org.joinmastodon.android.model.Preferences; +import org.joinmastodon.android.model.donations.DonationCampaign; +import org.joinmastodon.android.model.viewmodel.ListItem; +import org.joinmastodon.android.model.viewmodel.SectionHeaderListItem; +import org.joinmastodon.android.ui.M3AlertDialogBuilder; +import org.joinmastodon.android.ui.sheets.DonationSheet; +import org.joinmastodon.android.ui.sheets.DonationSuccessfulSheet; +import org.joinmastodon.android.ui.utils.UiUtils; +import org.joinmastodon.android.ui.viewcontrollers.ComposeLanguageAlertViewController; + +import java.util.ArrayList; +import java.util.Locale; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import me.grishka.appkit.Nav; +import me.grishka.appkit.api.Callback; +import me.grishka.appkit.api.ErrorResponse; +import me.grishka.appkit.utils.CubicBezierInterpolator; +import me.grishka.appkit.utils.MergeRecyclerAdapter; +import me.grishka.appkit.utils.SingleViewRecyclerAdapter; +import me.grishka.appkit.utils.V; + +public class SettingsAccountFragment extends BaseSettingsFragment{ + private static final int DONATION_RESULT=433; + private DonationSheet donationSheet; + private boolean loggedOut; + private ListItem languageItem; + private Locale postLanguage; + private ComposeLanguageAlertViewController.SelectedOption newPostLanguage; + + @Override + public void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + AccountSession account=AccountSessionManager.get(accountID); + setTitle(account.getFullUsername()); + if(account.preferences!=null && account.preferences.postingDefaultLanguage!=null){ + postLanguage=Locale.forLanguageTag(account.preferences.postingDefaultLanguage); + } + + ArrayList> items=new ArrayList<>(); + items.add(new SectionHeaderListItem(R.string.account_settings)); + + items.add(new ListItem<>(R.string.settings_privacy, 0, R.drawable.ic_privacy_tip_24px, this::onPrivacyClick)); + items.add(new ListItem<>(R.string.settings_filters, 0, R.drawable.ic_filter_alt_24px, this::onFiltersClick)); + items.add(new ListItem<>(R.string.settings_notifications, 0, R.drawable.ic_notifications_24px, this::onNotificationsClick)); + items.add(languageItem=new ListItem<>(getString(R.string.default_post_language), postLanguage!=null ? postLanguage.getDisplayName(Locale.getDefault()) : null, R.drawable.ic_language_24px, this::onDefaultLanguageClick)); + + items.add(new SectionHeaderListItem(account.domain)); + items.add(new ListItem<>(getString(R.string.settings_about_this_server), getString(R.string.settings_server_explanation), R.drawable.ic_dns_24px, this::onServerClick)); + if(account.isEligibleForDonations()){ + items.add(new ListItem<>(R.string.settings_donate, 0, R.drawable.ic_volunteer_activism_24px, this::onDonateClick)); + } + + items.add(new SectionHeaderListItem(R.string.manage_account)); + items.add(new ListItem<>(R.string.switch_to_this_account, 0, R.drawable.ic_switch_account_24px, AccountSessionManager.getInstance().getLastActiveAccountID().equals(accountID) ? null : this::onSwitchAccountClick)); + items.add(new ListItem<>(R.string.delete_account, 0, R.drawable.ic_delete_forever_24px, this::onDeleteAccountClick, R.attr.colorM3Error, false)); + items.add(new ListItem<>(R.string.log_out, 0, R.drawable.ic_logout_24px, this::onLogOutClick, R.attr.colorM3Error, false)); + + onDataLoaded(items); + } + + @Override + protected void doLoadData(int offset, int count){} + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data){ + if(requestCode==DONATION_RESULT){ + if(donationSheet!=null) + donationSheet.dismissWithoutAnimation(); + if(resultCode==Activity.RESULT_OK){ + new DonationSuccessfulSheet(getActivity(), accountID, data.getStringExtra("postText")).showWithoutAnimation(); + } + } + } + + @Override + protected void onHidden(){ + super.onHidden(); + if(!loggedOut){ + if(newPostLanguage!=null){ + AccountSession s=AccountSessionManager.get(accountID); + if(s.preferences==null) + s.preferences=new Preferences(); + s.preferences.postingDefaultLanguage=newPostLanguage.locale.toLanguageTag(); + s.savePreferencesLater(); + } + AccountSessionManager.get(accountID).savePreferencesIfPending(); + } + } + + @Override + protected void onUpdateToolbar(){ + super.onUpdateToolbar(); + toolbarTitleView.setAlpha(list.getChildCount()==0 || list.getChildAdapterPosition(list.getChildAt(0))==0 ? 0 : 1); + } + + @Override + protected RecyclerView.Adapter getAdapter(){ + TextView largeTitle=(TextView) getToolbarLayoutInflater().inflate(R.layout.large_title, list, false); + largeTitle.setText(getTitle()); + largeTitle.setPadding(largeTitle.getPaddingLeft(), largeTitle.getPaddingTop(), largeTitle.getPaddingRight(), 0); + + MergeRecyclerAdapter adapter=new MergeRecyclerAdapter(); + adapter.addAdapter(new SingleViewRecyclerAdapter(largeTitle)); + adapter.addAdapter(super.getAdapter()); + return adapter; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState){ + super.onViewCreated(view, savedInstanceState); + list.addOnScrollListener(new RecyclerView.OnScrollListener(){ + private boolean titleVisible=true; + + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){ + boolean newTitleVisible=list.getChildAdapterPosition(list.getChildAt(0))==0; + if(newTitleVisible!=titleVisible){ + titleVisible=newTitleVisible; + toolbarTitleView.animate().alpha(titleVisible ? 0 : 1).setDuration(250).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); + } + } + }); + } + + private Bundle makeFragmentArgs(){ + Bundle args=new Bundle(); + args.putString("account", accountID); + return args; + } + + private void onPrivacyClick(ListItem item_){ + Nav.go(getActivity(), SettingsPrivacyFragment.class, makeFragmentArgs()); + } + + private void onFiltersClick(ListItem item_){ + Nav.go(getActivity(), SettingsFiltersFragment.class, makeFragmentArgs()); + } + + private void onNotificationsClick(ListItem item_){ + Nav.go(getActivity(), SettingsNotificationsFragment.class, makeFragmentArgs()); + } + + private void onDefaultLanguageClick(ListItem item){ + ComposeLanguageAlertViewController vc=new ComposeLanguageAlertViewController(getActivity(), null, newPostLanguage==null ? new ComposeLanguageAlertViewController.SelectedOption(-1, postLanguage, null) : newPostLanguage, null); + AlertDialog dlg=new M3AlertDialogBuilder(getActivity()) + .setTitle(R.string.default_post_language) + .setView(vc.getView()) + .setPositiveButton(R.string.cancel, null) + .show(); + vc.setSelectionListener(opt->{ + if(!opt.locale.equals(postLanguage)){ + newPostLanguage=opt; + languageItem.subtitle=newPostLanguage.locale.getDisplayLanguage(Locale.getDefault()); + rebindItem(languageItem); + } + dlg.dismiss(); + }); + } + + private void onServerClick(ListItem item_){ + Nav.go(getActivity(), SettingsServerFragment.class, makeFragmentArgs()); + } + + private boolean useStagingEnvironmentForDonations(){ + return (BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")) && getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE).getBoolean("donationsStaging", false); + } + + private void onDonateClick(ListItem item){ + GetDonationCampaigns req=new GetDonationCampaigns(Locale.getDefault().toLanguageTag().replace('-', '_'), String.valueOf(AccountSessionManager.get(accountID).getDonationSeed()), "menu"); + if(useStagingEnvironmentForDonations()){ + req.setStaging(true); + } + req.setCallback(new Callback<>(){ + @Override + public void onSuccess(DonationCampaign result){ + Activity activity=getActivity(); + if(activity==null) + return; + if(result==null){ + Toast.makeText(activity, "No campaign available (server misconfiguration?)", Toast.LENGTH_SHORT).show(); + return; + } + donationSheet=new DonationSheet(getActivity(), result, accountID, intent->startActivityForResult(intent, DONATION_RESULT)); + donationSheet.setOnDismissListener(dialog->donationSheet=null); + donationSheet.show(); + } + + @Override + public void onError(ErrorResponse error){ + error.showToast(getActivity()); + } + }) + .wrapProgress(getActivity(), R.string.loading, true) + .execNoAuth(""); + } + + private void onSwitchAccountClick(ListItem item){ + if(AccountSessionManager.getInstance().tryGetAccount(accountID)!=null){ + AccountSessionManager.getInstance().setLastActiveAccountID(accountID); + ((MainActivity)getActivity()).restartHomeFragment(); + } + } + + private void onDeleteAccountClick(ListItem item){ + AccountSession session=AccountSessionManager.getInstance().getAccount(accountID); + UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/settings/delete"); + } + + private void onLogOutClick(ListItem item_){ + AccountSession session=AccountSessionManager.getInstance().getAccount(accountID); + new M3AlertDialogBuilder(getActivity()) + .setMessage(getString(R.string.confirm_log_out, session.getFullUsername())) + .setPositiveButton(R.string.log_out, (dialog, which)->AccountSessionManager.get(accountID).logOut(getActivity(), ()->{ + loggedOut=true; + ((MainActivity)getActivity()).restartHomeFragment(); + })) + .setNegativeButton(R.string.cancel, null) + .show(); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBehaviorFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBehaviorFragment.java index df84ef5ee..ebb1d23c0 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBehaviorFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBehaviorFragment.java @@ -1,6 +1,5 @@ package org.joinmastodon.android.fragments.settings; -import android.app.AlertDialog; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -13,38 +12,25 @@ import android.widget.TextView; import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.R; -import org.joinmastodon.android.api.session.AccountSession; -import org.joinmastodon.android.api.session.AccountSessionManager; -import org.joinmastodon.android.model.Preferences; import org.joinmastodon.android.model.viewmodel.CheckableListItem; import org.joinmastodon.android.model.viewmodel.ListItem; import org.joinmastodon.android.ui.M3AlertDialogBuilder; -import org.joinmastodon.android.ui.viewcontrollers.ComposeLanguageAlertViewController; import java.util.List; -import java.util.Locale; import androidx.annotation.NonNull; import androidx.annotation.Nullable; public class SettingsBehaviorFragment extends BaseSettingsFragment{ - private ListItem languageItem, customTabsItem; + private ListItem customTabsItem; private CheckableListItem altTextItem, playGifsItem, confirmUnfollowItem, confirmBoostItem, confirmDeleteItem; - private Locale postLanguage; - private ComposeLanguageAlertViewController.SelectedOption newPostLanguage; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setTitle(R.string.settings_behavior); - AccountSession s=AccountSessionManager.get(accountID); - if(s.preferences!=null && s.preferences.postingDefaultLanguage!=null){ - postLanguage=Locale.forLanguageTag(s.preferences.postingDefaultLanguage); - } - onDataLoaded(List.of( - languageItem=new ListItem<>(getString(R.string.default_post_language), postLanguage!=null ? postLanguage.getDisplayName(Locale.getDefault()) : null, R.drawable.ic_language_24px, this::onDefaultLanguageClick), customTabsItem=new ListItem<>(R.string.settings_custom_tabs, GlobalUserPreferences.useCustomTabs ? R.string.in_app_browser : R.string.system_browser, R.drawable.ic_open_in_browser_24px, this::onCustomTabsClick), altTextItem=new CheckableListItem<>(R.string.settings_alt_text_reminders, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.altTextReminders, R.drawable.ic_alt_24px, this::toggleCheckableItem), playGifsItem=new CheckableListItem<>(R.string.settings_gif, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.playGifs, R.drawable.ic_animation_24px, this::toggleCheckableItem), @@ -57,25 +43,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment{ @Override protected void doLoadData(int offset, int count){} - private void onDefaultLanguageClick(ListItem item){ - ComposeLanguageAlertViewController vc=new ComposeLanguageAlertViewController(getActivity(), null, newPostLanguage==null ? new ComposeLanguageAlertViewController.SelectedOption(-1, postLanguage, null) : newPostLanguage, null); - AlertDialog dlg=new M3AlertDialogBuilder(getActivity()) - .setTitle(R.string.default_post_language) - .setView(vc.getView()) - .setPositiveButton(R.string.cancel, null) - .show(); - vc.setSelectionListener(opt->{ - if(!opt.locale.equals(postLanguage)){ - newPostLanguage=opt; - languageItem.subtitle=newPostLanguage.locale.getDisplayLanguage(Locale.getDefault()); - rebindItem(languageItem); - } - dlg.dismiss(); - }); - } - private void onCustomTabsClick(ListItem item){ -// GlobalUserPreferences.useCustomTabs=customTabsItem.checked; Intent intent=new Intent(Intent.ACTION_VIEW, Uri.parse("http://example.com")); ResolveInfo info=getActivity().getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); final String browserName; @@ -125,12 +93,5 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment{ GlobalUserPreferences.confirmBoost=confirmBoostItem.checked; GlobalUserPreferences.confirmDeletePost=confirmDeleteItem.checked; GlobalUserPreferences.save(); - if(newPostLanguage!=null){ - AccountSession s=AccountSessionManager.get(accountID); - if(s.preferences==null) - s.preferences=new Preferences(); - s.preferences.postingDefaultLanguage=newPostLanguage.locale.toLanguageTag(); - s.savePreferencesLater(); - } } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDisplayFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDisplayFragment.java index ccea1052c..d081f09cc 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDisplayFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDisplayFragment.java @@ -13,9 +13,6 @@ import org.joinmastodon.android.E; import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.MastodonApp; import org.joinmastodon.android.R; -import org.joinmastodon.android.api.session.AccountLocalPreferences; -import org.joinmastodon.android.api.session.AccountSession; -import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent; import org.joinmastodon.android.model.viewmodel.CheckableListItem; import org.joinmastodon.android.model.viewmodel.ListItem; @@ -36,8 +33,6 @@ public class SettingsDisplayFragment extends BaseSettingsFragment{ public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setTitle(R.string.settings_display); - AccountSession s=AccountSessionManager.get(accountID); - AccountLocalPreferences lp=s.getLocalPreferences(); List> items=new ArrayList<>(); items.add(themeItem=new ListItem<>(R.string.settings_theme, getAppearanceValue(), R.drawable.ic_dark_mode_24px, this::onAppearanceClick)); if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.S){ @@ -47,10 +42,10 @@ public class SettingsDisplayFragment extends BaseSettingsFragment{ })); dynamicColorsItem.checkedChangeListener=this::setUseDynamicColors; } - items.add(showCWsItem=new CheckableListItem<>(R.string.settings_show_cws, 0, CheckableListItem.Style.SWITCH, lp.showCWs, R.drawable.ic_warning_24px, this::toggleCheckableItem)); - items.add(hideSensitiveMediaItem=new CheckableListItem<>(R.string.settings_hide_sensitive_media, 0, CheckableListItem.Style.SWITCH, lp.hideSensitiveMedia, R.drawable.ic_no_adult_content_24px, this::toggleCheckableItem)); - items.add(interactionCountsItem=new CheckableListItem<>(R.string.settings_show_interaction_counts, 0, CheckableListItem.Style.SWITCH, lp.showInteractionCounts, R.drawable.ic_social_leaderboard_24px, this::toggleCheckableItem)); - items.add(emojiInNamesItem=new CheckableListItem<>(R.string.settings_show_emoji_in_names, 0, CheckableListItem.Style.SWITCH, lp.customEmojiInNames, R.drawable.ic_emoticon_24px, this::toggleCheckableItem)); + items.add(showCWsItem=new CheckableListItem<>(R.string.settings_show_cws, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showCWs, R.drawable.ic_warning_24px, this::toggleCheckableItem)); + items.add(hideSensitiveMediaItem=new CheckableListItem<>(R.string.settings_hide_sensitive_media, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.hideSensitiveMedia, R.drawable.ic_no_adult_content_24px, this::toggleCheckableItem)); + items.add(interactionCountsItem=new CheckableListItem<>(R.string.settings_show_interaction_counts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showInteractionCounts, R.drawable.ic_social_leaderboard_24px, this::toggleCheckableItem)); + items.add(emojiInNamesItem=new CheckableListItem<>(R.string.settings_show_emoji_in_names, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.customEmojiInNames, R.drawable.ic_emoticon_24px, this::toggleCheckableItem)); onDataLoaded(items); } @@ -70,13 +65,11 @@ public class SettingsDisplayFragment extends BaseSettingsFragment{ @Override protected void onHidden(){ super.onHidden(); - AccountSession s=AccountSessionManager.get(accountID); - AccountLocalPreferences lp=s.getLocalPreferences(); - lp.showCWs=showCWsItem.checked; - lp.hideSensitiveMedia=hideSensitiveMediaItem.checked; - lp.showInteractionCounts=interactionCountsItem.checked; - lp.customEmojiInNames=emojiInNamesItem.checked; - lp.save(); + GlobalUserPreferences.showCWs=showCWsItem.checked; + GlobalUserPreferences.hideSensitiveMedia=hideSensitiveMediaItem.checked; + GlobalUserPreferences.showInteractionCounts=interactionCountsItem.checked; + GlobalUserPreferences.customEmojiInNames=emojiInNamesItem.checked; + GlobalUserPreferences.save(); E.post(new StatusDisplaySettingsChangedEvent(accountID)); } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsMainFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsMainFragment.java index 141826a53..dd4d7f223 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsMainFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsMainFragment.java @@ -1,53 +1,44 @@ package org.joinmastodon.android.fragments.settings; -import android.app.Activity; import android.content.Context; -import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; -import android.widget.Toast; import com.squareup.otto.Subscribe; import org.joinmastodon.android.BuildConfig; import org.joinmastodon.android.E; -import org.joinmastodon.android.MainActivity; +import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.R; -import org.joinmastodon.android.api.requests.catalog.GetDonationCampaigns; import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.events.SelfUpdateStateChangedEvent; -import org.joinmastodon.android.model.donations.DonationCampaign; +import org.joinmastodon.android.fragments.SplashFragment; import org.joinmastodon.android.model.viewmodel.ListItem; -import org.joinmastodon.android.ui.M3AlertDialogBuilder; -import org.joinmastodon.android.ui.sheets.AccountSwitcherSheet; -import org.joinmastodon.android.ui.sheets.DonationSheet; -import org.joinmastodon.android.ui.sheets.DonationSuccessfulSheet; +import org.joinmastodon.android.model.viewmodel.SectionHeaderListItem; +import org.joinmastodon.android.model.viewmodel.SettingsAccountListItem; import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter; import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.updater.GithubSelfUpdater; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import androidx.recyclerview.widget.RecyclerView; import me.grishka.appkit.Nav; -import me.grishka.appkit.api.Callback; -import me.grishka.appkit.api.ErrorResponse; +import me.grishka.appkit.imageloader.requests.ImageLoaderRequest; +import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest; import me.grishka.appkit.utils.MergeRecyclerAdapter; +import me.grishka.appkit.utils.V; -public class SettingsMainFragment extends BaseSettingsFragment{ - private static final int DONATION_RESULT=433; +public class SettingsMainFragment extends BaseSettingsFragment{ - private boolean loggedOut; private HideableSingleViewRecyclerAdapter bannerAdapter; private Button updateButton1, updateButton2; private TextView updateText; - private DonationSheet donationSheet; private Runnable updateDownloadProgressUpdater=new Runnable(){ @Override public void run(){ @@ -63,27 +54,35 @@ public class SettingsMainFragment extends BaseSettingsFragment{ public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setTitle(R.string.settings); - setSubtitle(AccountSessionManager.get(accountID).getFullUsername()); - ArrayList> items=new ArrayList<>(); - if(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")){ - items.add(new ListItem<>("Debug settings", null, R.drawable.ic_settings_24px, i->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null, 0, true)); + ArrayList> items=new ArrayList<>(); + items.add(new SectionHeaderListItem(R.string.settings_accounts)); + for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){ + ImageLoaderRequest req; + if(session.self.avatar!=null) + req=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? session.self.avatar : session.self.avatarStatic, V.dp(50), V.dp(50)); + else + req=null; + items.add(new SettingsAccountListItem<>(session.getFullUsername(), null, req, this::onAccountClick, session, false)); } + items.addAll(List.of( - new ListItem<>(R.string.settings_behavior, 0, R.drawable.ic_settings_24px, this::onBehaviorClick), - new ListItem<>(R.string.settings_display, 0, R.drawable.ic_style_24px, this::onDisplayClick), - new ListItem<>(R.string.settings_privacy, 0, R.drawable.ic_privacy_tip_24px, this::onPrivacyClick), - new ListItem<>(R.string.settings_filters, 0, R.drawable.ic_filter_alt_24px, this::onFiltersClick), - new ListItem<>(R.string.settings_notifications, 0, R.drawable.ic_notifications_24px, this::onNotificationsClick), - new ListItem<>(AccountSessionManager.get(accountID).domain, getString(R.string.settings_server_explanation), R.drawable.ic_dns_24px, this::onServerClick), - new ListItem<>(getString(R.string.about_app, getString(R.string.app_name)), null, R.drawable.ic_info_24px, this::onAboutClick, null, 0, true) + new ListItem<>(R.string.settings_add_account, 0, R.drawable.ic_add_24px, this::onAddAccountClick), + + new SectionHeaderListItem(R.string.settings_app_settings), + new ListItem<>(R.string.settings_behavior, 0, R.drawable.ic_tune_24px, this::onBehaviorClick), + new ListItem<>(R.string.settings_display, 0, R.drawable.ic_style_24px, this::onDisplayClick) + )); if(AccountSessionManager.get(accountID).isEligibleForDonations()){ - items.add(new ListItem<>(R.string.settings_donate, 0, R.drawable.ic_volunteer_activism_24px, this::onDonateClick)); - items.add(new ListItem<>(R.string.settings_manage_donations, 0, R.drawable.ic_settings_heart_24px, this::onManageDonationClick, 0, true)); + items.add(new ListItem<>(R.string.settings_manage_donations, 0, R.drawable.ic_settings_heart_24px, this::onManageDonationClick)); } - items.add(new ListItem<>(R.string.manage_accounts, 0, R.drawable.ic_switch_account_24px, this::onManageAccountsClick)); - items.add(new ListItem<>(R.string.log_out, 0, R.drawable.ic_logout_24px, this::onLogOutClick, R.attr.colorM3Error, false)); - onDataLoaded(items); + items.add(new ListItem<>(getString(R.string.about_app, getString(R.string.app_name)), null, R.drawable.ic_info_24px, this::onAboutClick, null)); + if(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")){ + items.add(new ListItem<>("Debug settings", null, R.drawable.ic_bug_report_24px, i->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null)); + } + + //noinspection unchecked + onDataLoaded((List>)(Object)items); AccountSession session=AccountSessionManager.get(accountID); session.reloadPreferences(null); @@ -100,13 +99,6 @@ public class SettingsMainFragment extends BaseSettingsFragment{ @Override protected void doLoadData(int offset, int count){} - @Override - protected void onHidden(){ - super.onHidden(); - if(!loggedOut) - AccountSessionManager.get(accountID).savePreferencesIfPending(); - } - @Override protected RecyclerView.Adapter getAdapter(){ View banner=getActivity().getLayoutInflater().inflate(R.layout.item_settings_banner, list, false); @@ -137,23 +129,22 @@ public class SettingsMainFragment extends BaseSettingsFragment{ } } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data){ - if(requestCode==DONATION_RESULT){ - if(donationSheet!=null) - donationSheet.dismissWithoutAnimation(); - if(resultCode==Activity.RESULT_OK){ - new DonationSuccessfulSheet(getActivity(), accountID, data.getStringExtra("postText")).showWithoutAnimation(); - } - } - } - private Bundle makeFragmentArgs(){ Bundle args=new Bundle(); args.putString("account", accountID); return args; } + private void onAccountClick(SettingsAccountListItem item){ + Bundle args=new Bundle(); + args.putString("account", item.parentObject.getID()); + Nav.go(getActivity(), SettingsAccountFragment.class, args); + } + + private void onAddAccountClick(ListItem item_){ + Nav.go(getActivity(), SplashFragment.class, null); + } + private void onBehaviorClick(ListItem item_){ Nav.go(getActivity(), SettingsBehaviorFragment.class, makeFragmentArgs()); } @@ -162,73 +153,16 @@ public class SettingsMainFragment extends BaseSettingsFragment{ Nav.go(getActivity(), SettingsDisplayFragment.class, makeFragmentArgs()); } - private void onPrivacyClick(ListItem item_){ - Nav.go(getActivity(), SettingsPrivacyFragment.class, makeFragmentArgs()); - } - - private void onFiltersClick(ListItem item_){ - Nav.go(getActivity(), SettingsFiltersFragment.class, makeFragmentArgs()); - } - - private void onNotificationsClick(ListItem item_){ - Nav.go(getActivity(), SettingsNotificationsFragment.class, makeFragmentArgs()); - } - - private void onServerClick(ListItem item_){ - Nav.go(getActivity(), SettingsServerFragment.class, makeFragmentArgs()); - } - private void onAboutClick(ListItem item_){ Nav.go(getActivity(), SettingsAboutAppFragment.class, makeFragmentArgs()); } - private void onManageAccountsClick(ListItem item){ - new AccountSwitcherSheet(getActivity(), null).setOnLoggedOutCallback(()->loggedOut=true).show(); - } - - private void onLogOutClick(ListItem item_){ - AccountSession session=AccountSessionManager.getInstance().getAccount(accountID); - new M3AlertDialogBuilder(getActivity()) - .setMessage(getString(R.string.confirm_log_out, session.getFullUsername())) - .setPositiveButton(R.string.log_out, (dialog, which)->AccountSessionManager.get(accountID).logOut(getActivity(), ()->{ - loggedOut=true; - ((MainActivity)getActivity()).restartHomeFragment(); - })) - .setNegativeButton(R.string.cancel, null) - .show(); - } - - private void onDonateClick(ListItem item){ - GetDonationCampaigns req=new GetDonationCampaigns(Locale.getDefault().toLanguageTag().replace('-', '_'), String.valueOf(AccountSessionManager.get(accountID).getDonationSeed()), "menu"); - if(getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE).getBoolean("donationsStaging", false)){ - req.setStaging(true); - } - req.setCallback(new Callback<>(){ - @Override - public void onSuccess(DonationCampaign result){ - Activity activity=getActivity(); - if(activity==null) - return; - if(result==null){ - Toast.makeText(activity, "No campaign available (server misconfiguration?)", Toast.LENGTH_SHORT).show(); - return; - } - donationSheet=new DonationSheet(getActivity(), result, accountID, intent->startActivityForResult(intent, DONATION_RESULT)); - donationSheet.setOnDismissListener(dialog->donationSheet=null); - donationSheet.show(); - } - - @Override - public void onError(ErrorResponse error){ - error.showToast(getActivity()); - } - }) - .wrapProgress(getActivity(), R.string.loading, true) - .execNoAuth(""); + private boolean useStagingEnvironmentForDonations(){ + return (BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")) && getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE).getBoolean("donationsStaging", false); } private void onManageDonationClick(ListItem item){ - UiUtils.launchWebBrowser(getActivity(), "https://sponsor.staging.joinmastodon.org/donate/manage"); + UiUtils.launchWebBrowser(getActivity(), useStagingEnvironmentForDonations() ? "https://sponsor.staging.joinmastodon.org/donate/manage" : "https://sponsor.joinmastodon.org/donate/manage"); } @Subscribe diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/AccountViewModel.java b/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/AccountViewModel.java index 0012f0330..db0be60c8 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/AccountViewModel.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/AccountViewModel.java @@ -5,7 +5,6 @@ import android.text.Spannable; import android.text.SpannableStringBuilder; import org.joinmastodon.android.GlobalUserPreferences; -import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.AccountField; import org.joinmastodon.android.ui.text.HtmlParser; @@ -33,7 +32,7 @@ public class AccountViewModel{ this.account=account; avaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic, V.dp(50), V.dp(50)); emojiHelper=new CustomEmojiHelper(); - if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames) + if(GlobalUserPreferences.customEmojiInNames) parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis); else parsedName=account.displayName; diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/CardViewModel.java b/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/CardViewModel.java index 902e18109..afcfb7e6d 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/CardViewModel.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/CardViewModel.java @@ -4,7 +4,6 @@ import android.text.SpannableStringBuilder; import android.text.TextUtils; import org.joinmastodon.android.GlobalUserPreferences; -import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Card; import org.joinmastodon.android.ui.text.HtmlParser; @@ -31,7 +30,7 @@ public class CardViewModel{ if(authorAccount!=null){ parsedAuthorName=new SpannableStringBuilder(authorAccount.displayName); - if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames) + if(GlobalUserPreferences.customEmojiInNames) HtmlParser.parseCustomEmoji(parsedAuthorName, authorAccount.emojis); authorNameEmojiHelper.setText(parsedAuthorName); authorAvaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? authorAccount.avatar : authorAccount.avatarStatic, V.dp(50), V.dp(50)); diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/SectionHeaderListItem.java b/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/SectionHeaderListItem.java new file mode 100644 index 000000000..4462976fd --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/SectionHeaderListItem.java @@ -0,0 +1,20 @@ +package org.joinmastodon.android.model.viewmodel; + +import org.joinmastodon.android.R; + +import androidx.annotation.StringRes; + +public class SectionHeaderListItem extends ListItem{ + public SectionHeaderListItem(String title){ + super(title, null, null); + } + + public SectionHeaderListItem(@StringRes int title){ + super(title, 0, null); + } + + @Override + public int getItemViewType(){ + return R.id.list_item_section_header; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/SettingsAccountListItem.java b/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/SettingsAccountListItem.java new file mode 100644 index 000000000..827671aca --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/model/viewmodel/SettingsAccountListItem.java @@ -0,0 +1,21 @@ +package org.joinmastodon.android.model.viewmodel; + +import org.joinmastodon.android.R; + +import java.util.function.Consumer; + +import me.grishka.appkit.imageloader.requests.ImageLoaderRequest; + +public class SettingsAccountListItem extends ListItem{ + public ImageLoaderRequest avatar; + + public SettingsAccountListItem(String title, String subtitle, ImageLoaderRequest avatar, Consumer> onClick, T parentObject, boolean dividerAfter){ + super(title, subtitle, 0, (Consumer>)(Object)onClick, parentObject, 0, dividerAfter); + this.avatar=avatar; + } + + @Override + public int getItemViewType(){ + return R.id.list_item_settings_account; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/adapters/GenericListItemsAdapter.java b/mastodon/src/main/java/org/joinmastodon/android/ui/adapters/GenericListItemsAdapter.java index bd057a428..285ad0ba7 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/adapters/GenericListItemsAdapter.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/adapters/GenericListItemsAdapter.java @@ -5,17 +5,19 @@ import android.view.ViewGroup; import org.joinmastodon.android.R; import org.joinmastodon.android.model.viewmodel.AvatarPileListItem; import org.joinmastodon.android.model.viewmodel.ListItem; +import org.joinmastodon.android.model.viewmodel.SettingsAccountListItem; import org.joinmastodon.android.ui.viewholders.AvatarPileListItemViewHolder; import org.joinmastodon.android.ui.viewholders.CheckboxOrRadioListItemViewHolder; import org.joinmastodon.android.ui.viewholders.ListItemViewHolder; import org.joinmastodon.android.ui.viewholders.OptionsListItemViewHolder; +import org.joinmastodon.android.ui.viewholders.SectionHeaderListItemViewHolder; +import org.joinmastodon.android.ui.viewholders.SettingsAccountListItemViewHolder; import org.joinmastodon.android.ui.viewholders.SimpleListItemViewHolder; import org.joinmastodon.android.ui.viewholders.SwitchListItemViewHolder; import java.util.List; import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter; import me.grishka.appkit.imageloader.ListImageLoaderWrapper; import me.grishka.appkit.imageloader.requests.ImageLoaderRequest; @@ -49,6 +51,10 @@ public class GenericListItemsAdapter extends UsableRecyclerView.Adapter extends UsableRecyclerView.Adapter item=items.get(position); if(item instanceof AvatarPileListItem avatarPileListItem) return avatarPileListItem.avatars.size(); + if(item instanceof SettingsAccountListItem) + return 1; return 0; } @@ -82,6 +90,8 @@ public class GenericListItemsAdapter extends UsableRecyclerView.Adapter item=items.get(position); if(item instanceof AvatarPileListItem avatarPileListItem) return avatarPileListItem.avatars.get(image); + if(item instanceof SettingsAccountListItem accountItem) + return accountItem.avatar; return null; } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java index 1292eb726..a9609a26d 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java @@ -75,7 +75,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ this.accountID=accountID; parsedName=new SpannableStringBuilder(user.displayName); this.status=status; - if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames) + if(GlobalUserPreferences.customEmojiInNames) HtmlParser.parseCustomEmoji(parsedName, user.emojis); emojiHelper.setText(parsedName); if(status!=null){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/InlineStatusStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/InlineStatusStatusDisplayItem.java index e8d6ad10f..3b8083727 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/InlineStatusStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/InlineStatusStatusDisplayItem.java @@ -9,7 +9,6 @@ import android.widget.TextView; import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.R; -import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.model.Status; import org.joinmastodon.android.ui.OutlineProviders; @@ -36,7 +35,7 @@ public class InlineStatusStatusDisplayItem extends StatusDisplayItem{ this.status=status; parsedName=new SpannableStringBuilder(status.account.displayName); - if(AccountSessionManager.get(parentFragment.getAccountID()).getLocalPreferences().customEmojiInNames) + if(GlobalUserPreferences.customEmojiInNames) HtmlParser.parseCustomEmoji(parsedName, status.account.emojis); parsedPostText=HtmlParser.parse(status.content, status.emojis, status.mentions, status.tags, parentFragment.getAccountID(), status.getContentStatus(), parentFragment.getActivity()); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/ReblogOrReplyLineStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/ReblogOrReplyLineStatusDisplayItem.java index b5bd2a7ff..3cbf05676 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/ReblogOrReplyLineStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/ReblogOrReplyLineStatusDisplayItem.java @@ -7,8 +7,8 @@ import android.text.SpannableStringBuilder; import android.view.ViewGroup; import android.widget.TextView; +import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.R; -import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.model.Emoji; import org.joinmastodon.android.ui.text.HtmlParser; @@ -31,7 +31,7 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{ public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List emojis, @DrawableRes int icon){ super(parentID, parentFragment); SpannableStringBuilder ssb=new SpannableStringBuilder(text); - if(AccountSessionManager.get(parentFragment.getAccountID()).getLocalPreferences().customEmojiInNames) + if(GlobalUserPreferences.customEmojiInNames) HtmlParser.parseCustomEmoji(ssb, emojis); this.text=ssb; emojiHelper.setText(ssb); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java index b19032bd9..a44f4967b 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java @@ -8,8 +8,8 @@ import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; +import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.R; -import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.fragments.ThreadFragment; import org.joinmastodon.android.model.Account; @@ -97,7 +97,7 @@ public abstract class StatusDisplayItem{ ArrayList items=new ArrayList<>(); Status statusForContent=status.getContentStatus(); HeaderStatusDisplayItem header=null; - boolean hideCounts=!AccountSessionManager.get(accountID).getLocalPreferences().showInteractionCounts; + boolean hideCounts=!GlobalUserPreferences.showInteractionCounts; if((flags & FLAG_NO_HEADER)==0){ if(status.reblog!=null){ items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.user_boosted, status.account.displayName), status.account.emojis, R.drawable.ic_repeat_wght700_20px)); @@ -134,7 +134,7 @@ public abstract class StatusDisplayItem{ SpoilerStatusDisplayItem spoilerItem=new SpoilerStatusDisplayItem(parentID, fragment, null, status, statusForContent, Type.SPOILER, Status.SpoilerType.CONTENT_WARNING); contentItems.add(spoilerItem); contentItems=spoilerItem.contentItems; - if(!AccountSessionManager.get(accountID).getLocalPreferences().showCWs && !filtered){ + if(!GlobalUserPreferences.showCWs && !filtered){ status.revealedSpoilers.add(Status.SpoilerType.CONTENT_WARNING); needAddCWItems=true; } @@ -158,7 +158,7 @@ public abstract class StatusDisplayItem{ if((flags & FLAG_MEDIA_FORCE_HIDDEN)!=0){ mediaGrid.sensitiveTitle=fragment.getString(R.string.media_hidden); mediaGrid.sensitiveRevealed=false; - }else if(statusForContent.sensitive && !AccountSessionManager.get(accountID).getLocalPreferences().hideSensitiveMedia){ + }else if(statusForContent.sensitive && !GlobalUserPreferences.hideSensitiveMedia){ mediaGrid.sensitiveRevealed=true; } contentItems.add(mediaGrid); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/NonMutualPreReplySheet.java b/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/NonMutualPreReplySheet.java index 9e358be17..8da92e329 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/NonMutualPreReplySheet.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/NonMutualPreReplySheet.java @@ -11,8 +11,8 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.R; -import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.model.Account; import org.joinmastodon.android.ui.OutlineProviders; import org.joinmastodon.android.ui.text.HtmlParser; @@ -57,7 +57,7 @@ public class NonMutualPreReplySheet extends PreReplySheet{ name.setEllipsize(TextUtils.TruncateAt.END); name.setTextAppearance(R.style.m3_title_medium); name.setTextColor(UiUtils.getThemeColor(context, R.attr.colorM3OnSurface)); - if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames){ + if(GlobalUserPreferences.customEmojiInNames){ name.setText(HtmlParser.parseCustomEmoji(account.displayName, account.emojis)); UiUtils.loadCustomEmojiInTextView(name); }else{ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/viewholders/ListItemViewHolder.java b/mastodon/src/main/java/org/joinmastodon/android/ui/viewholders/ListItemViewHolder.java index f703b2f9e..884b700b9 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/viewholders/ListItemViewHolder.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/viewholders/ListItemViewHolder.java @@ -28,7 +28,7 @@ public abstract class ListItemViewHolder> extends Bindable title=findViewById(R.id.title); subtitle=findViewById(R.id.subtitle); icon=findViewById(R.id.icon); - view=(LinearLayout) itemView; + view=itemView instanceof LinearLayout ll ? ll : null; } @Override @@ -52,12 +52,7 @@ public abstract class ListItemViewHolder> extends Bindable subtitle.setText(item.subtitle); } - if(item.iconRes!=0){ - icon.setVisibility(View.VISIBLE); - icon.setImageResource(item.iconRes); - }else{ - icon.setVisibility(View.GONE); - } + bindIcon(item); if(item.colorOverrideAttr!=0){ int color=UiUtils.getThemeColor(view.getContext(), item.colorOverrideAttr); @@ -68,6 +63,15 @@ public abstract class ListItemViewHolder> extends Bindable view.setAlpha(item.isEnabled ? 1 : .4f); } + protected void bindIcon(T item){ + if(item.iconRes!=0){ + icon.setVisibility(View.VISIBLE); + icon.setImageResource(item.iconRes); + }else{ + icon.setVisibility(View.GONE); + } + } + @Override public boolean isEnabled(){ return item.isEnabled; diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/viewholders/SectionHeaderListItemViewHolder.java b/mastodon/src/main/java/org/joinmastodon/android/ui/viewholders/SectionHeaderListItemViewHolder.java new file mode 100644 index 000000000..0d463a2c2 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/viewholders/SectionHeaderListItemViewHolder.java @@ -0,0 +1,22 @@ +package org.joinmastodon.android.ui.viewholders; + +import android.content.Context; +import android.text.TextUtils; +import android.view.ViewGroup; + +import org.joinmastodon.android.R; +import org.joinmastodon.android.model.viewmodel.SectionHeaderListItem; + +public class SectionHeaderListItemViewHolder extends ListItemViewHolder{ + public SectionHeaderListItemViewHolder(Context context, ViewGroup parent){ + super(context, R.layout.item_generic_list_header, parent); + } + + @Override + public void onBind(SectionHeaderListItem item){ + if(TextUtils.isEmpty(item.title)) + title.setText(item.titleRes); + else + title.setText(item.title); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/viewholders/SettingsAccountListItemViewHolder.java b/mastodon/src/main/java/org/joinmastodon/android/ui/viewholders/SettingsAccountListItemViewHolder.java new file mode 100644 index 000000000..b69508b9e --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/viewholders/SettingsAccountListItemViewHolder.java @@ -0,0 +1,34 @@ +package org.joinmastodon.android.ui.viewholders; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.ViewGroup; + +import org.joinmastodon.android.R; +import org.joinmastodon.android.model.viewmodel.SettingsAccountListItem; +import org.joinmastodon.android.ui.OutlineProviders; + +import me.grishka.appkit.imageloader.ImageLoaderViewHolder; + +public class SettingsAccountListItemViewHolder extends ListItemViewHolder> implements ImageLoaderViewHolder{ + + public SettingsAccountListItemViewHolder(Context context, ViewGroup parent){ + super(context, R.layout.item_generic_list, parent); + icon.setOutlineProvider(OutlineProviders.OVAL); + icon.setClipToOutline(true); + icon.setImageTintList(null); + } + + @Override + protected void bindIcon(SettingsAccountListItem item){} + + @Override + public void setImage(int index, Drawable image){ + icon.setImageDrawable(image); + } + + @Override + public void clearImage(int index){ + icon.setImageResource(R.drawable.image_placeholder); + } +} diff --git a/mastodon/src/main/res/drawable/ic_bug_report_24px.xml b/mastodon/src/main/res/drawable/ic_bug_report_24px.xml new file mode 100644 index 000000000..bf600b76b --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_bug_report_24px.xml @@ -0,0 +1,9 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_delete_forever_24px.xml b/mastodon/src/main/res/drawable/ic_delete_forever_24px.xml new file mode 100644 index 000000000..263cd956a --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_delete_forever_24px.xml @@ -0,0 +1,9 @@ + + + diff --git a/mastodon/src/main/res/layout/item_generic_list_header.xml b/mastodon/src/main/res/layout/item_generic_list_header.xml new file mode 100644 index 000000000..9fac3f56c --- /dev/null +++ b/mastodon/src/main/res/layout/item_generic_list_header.xml @@ -0,0 +1,15 @@ + + \ No newline at end of file diff --git a/mastodon/src/main/res/layout/large_title.xml b/mastodon/src/main/res/layout/large_title.xml new file mode 100644 index 000000000..e8ca84de9 --- /dev/null +++ b/mastodon/src/main/res/layout/large_title.xml @@ -0,0 +1,12 @@ + + \ No newline at end of file diff --git a/mastodon/src/main/res/values/ids.xml b/mastodon/src/main/res/values/ids.xml index 7e618d9c2..89418b85c 100644 --- a/mastodon/src/main/res/values/ids.xml +++ b/mastodon/src/main/res/values/ids.xml @@ -27,6 +27,8 @@ + + diff --git a/mastodon/src/main/res/values/strings.xml b/mastodon/src/main/res/values/strings.xml index aa4104d62..0562a094b 100644 --- a/mastodon/src/main/res/values/strings.xml +++ b/mastodon/src/main/res/values/strings.xml @@ -814,6 +814,14 @@ Move and scale Choose Use system dynamic color + Accounts + Add account... + App settings + Account settings + About this server + Manage account + Switch to this account + Delete account %1$s and %2$,d other followed you %1$s and %2$,d others followed you