diff --git a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java index 53be8a16d..17edb9a96 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java +++ b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java @@ -52,6 +52,7 @@ public class GlobalUserPreferences{ public static boolean doubleTapToSwipe; public static boolean compactReblogReplyLine; public static boolean confirmBeforeReblog; + public static boolean hapticFeedback; public static boolean replyLineAboveHeader; public static boolean swapBookmarkWithBoostAction; public static boolean loadRemoteAccountFollowers; @@ -139,6 +140,7 @@ public class GlobalUserPreferences{ replyLineAboveHeader=prefs.getBoolean("replyLineAboveHeader", true); compactReblogReplyLine=prefs.getBoolean("compactReblogReplyLine", true); confirmBeforeReblog=prefs.getBoolean("confirmBeforeReblog", false); + hapticFeedback=prefs.getBoolean("hapticFeedback", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); swapBookmarkWithBoostAction=prefs.getBoolean("swapBookmarkWithBoostAction", false); loadRemoteAccountFollowers=prefs.getBoolean("loadRemoteAccountFollowers", true); mentionRebloggerAutomatically=prefs.getBoolean("mentionRebloggerAutomatically", false); diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/BehaviourFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/BehaviourFragment.java index ef6b82235..a289d1e42 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/BehaviourFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/BehaviourFragment.java @@ -1,5 +1,6 @@ package org.joinmastodon.android.fragments.settings; +import android.os.Build; import android.view.Gravity; import android.view.MenuItem; import android.view.ViewGroup; @@ -63,6 +64,10 @@ public class BehaviourFragment extends SettingsBaseFragment{ GlobalUserPreferences.save(); needAppRestart=true; })); + items.add(new SwitchItem(R.string.mo_haptic_feedback, R.string.mo_setting_haptic_feedback_summary, R.drawable.ic_fluent_phone_vibrate_24_filled, GlobalUserPreferences.hapticFeedback, i -> { + GlobalUserPreferences.hapticFeedback = i.checked; + GlobalUserPreferences.save(); + }, Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)); items.add(new SwitchItem(R.string.sk_settings_confirm_before_reblog, R.drawable.ic_fluent_checkmark_circle_24_regular, GlobalUserPreferences.confirmBeforeReblog, i->{ GlobalUserPreferences.confirmBeforeReblog=i.checked; GlobalUserPreferences.save(); 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 ae30f0689..3bd3f85a9 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 @@ -264,6 +264,15 @@ public abstract class SettingsBaseFragment extends MastodonToolbarFragment imple this.onChanged=onChanged; } + public SwitchItem(@StringRes int title, @StringRes int summary, @DrawableRes int icon, boolean checked, Consumer onChanged, boolean enabled){ + this.title=getString(title); + this.summary=getString(summary); + this.icon=icon; + this.checked=checked; + this.onChanged=onChanged; + this.enabled=enabled; + } + public SwitchItem(@StringRes int title, @DrawableRes int icon, boolean checked, Consumer onChanged, boolean enabled){ this.title=getString(title); this.icon=icon; diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java index 9f45de6fe..77f5028db 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java @@ -5,7 +5,9 @@ import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Bundle; +import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -244,12 +246,14 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ if(status == null) return; boost.setSelected(!status.reblogged); + vibrateForAction(boost, !status.reblogged); AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(status, !status.reblogged, null, r->boostConsumer(v, r)); } ); return; } boost.setSelected(!item.status.reblogged); + vibrateForAction(boost, !item.status.reblogged); AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, null, r->boostConsumer(v, r)); } @@ -361,6 +365,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ if(status == null) return; favorite.setSelected(!status.favourited); + vibrateForAction(favorite, !status.favourited); AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(status, !status.favourited, r->{ if (status.favourited) { v.startAnimation(GlobalUserPreferences.reduceMotion ? opacityIn : animSet); @@ -374,6 +379,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ return; } favorite.setSelected(!item.status.favourited); + vibrateForAction(favorite, !item.status.favourited); AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{ if (item.status.favourited) { v.startAnimation(GlobalUserPreferences.reduceMotion ? opacityIn : animSet); @@ -406,6 +412,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ if(status == null) return; bookmark.setSelected(!status.bookmarked); + vibrateForAction(bookmark, !status.bookmarked); AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(status, !status.bookmarked, r->{ v.startAnimation(opacityIn); }); @@ -414,6 +421,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ return; } bookmark.setSelected(!item.status.bookmarked); + vibrateForAction(bookmark, !item.status.bookmarked); AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{ v.startAnimation(opacityIn); }); @@ -459,5 +467,11 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ return R.string.button_share; return 0; } + + private static void vibrateForAction(View view, boolean isPositive) { + if (!GlobalUserPreferences.hapticFeedback) return; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return; + view.performHapticFeedback(isPositive ? HapticFeedbackConstants.CONFIRM : HapticFeedbackConstants.REJECT); + } } } diff --git a/mastodon/src/main/res/drawable/ic_fluent_phone_vibrate_24_filled.xml b/mastodon/src/main/res/drawable/ic_fluent_phone_vibrate_24_filled.xml new file mode 100644 index 000000000..c182f3802 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_phone_vibrate_24_filled.xml @@ -0,0 +1,9 @@ + + + diff --git a/mastodon/src/main/res/values/strings_mo.xml b/mastodon/src/main/res/values/strings_mo.xml index 89790e4d0..ced3fd17c 100644 --- a/mastodon/src/main/res/values/strings_mo.xml +++ b/mastodon/src/main/res/values/strings_mo.xml @@ -53,6 +53,7 @@ Open in App Double tap to swipe between tabs + Haptic feedback Swap bookmark with reblog action Download latest nightly release Load remote profile follows and followers @@ -83,6 +84,7 @@ Replies will be opted out of discovery features Show how many people interacted with a post in the timeline Swipe to change viewed timeline + Vibrate when interacting with posts Bookmark or reblog posts from the notification