diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt index 7f6ee589..292fe241 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt @@ -58,6 +58,7 @@ import com.keylesspalace.tusky.interfaces.LinkListener import com.keylesspalace.tusky.interfaces.ReselectableFragment import com.keylesspalace.tusky.pager.AccountPagerAdapter import com.keylesspalace.tusky.util.* +import com.keylesspalace.tusky.view.showMuteAccountDialog import com.keylesspalace.tusky.viewmodel.AccountViewModel import dagger.android.DispatchingAndroidInjector import dagger.android.HasAndroidInjector @@ -382,7 +383,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI invalidateOptionsMenu() accountMuteButton.setOnClickListener { - viewModel.changeMuteState() + viewModel.unmuteAccount() updateMuteButton() } } @@ -703,13 +704,15 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI private fun toggleMute() { if (viewModel.relationshipData.value?.data?.muting != true) { - AlertDialog.Builder(this) - .setMessage(getString(R.string.dialog_mute_warning, loadedAccount?.username)) - .setPositiveButton(android.R.string.ok) { _, _ -> viewModel.changeMuteState() } - .setNegativeButton(android.R.string.cancel, null) - .show() + loadedAccount?.let { + showMuteAccountDialog( + this, + it.username, + { notifications -> viewModel.muteAccount(notifications) } + ) + } } else { - viewModel.changeMuteState() + viewModel.unmuteAccount() } } diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java index 34338dbb..c4224c9c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java @@ -8,6 +8,7 @@ import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.view.ViewCompat; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; @@ -17,10 +18,14 @@ import com.keylesspalace.tusky.interfaces.AccountActionListener; import com.keylesspalace.tusky.util.CustomEmojiHelper; import com.keylesspalace.tusky.util.ImageLoadingHelper; +import java.util.HashMap; + public class MutesAdapter extends AccountAdapter { + private HashMap mutingNotificationsMap; public MutesAdapter(AccountActionListener accountActionListener) { super(accountActionListener); + mutingNotificationsMap = new HashMap(); } @NonNull @@ -45,19 +50,31 @@ public class MutesAdapter extends AccountAdapter { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { if (getItemViewType(position) == VIEW_TYPE_ACCOUNT) { MutedUserViewHolder holder = (MutedUserViewHolder) viewHolder; - holder.setupWithAccount(accountList.get(position)); + Account account = accountList.get(position); + holder.setupWithAccount(account, mutingNotificationsMap.get(account.getId())); holder.setupActionListener(accountActionListener); } } + public void updateMutingNotifications(String id, boolean mutingNotifications, int position) { + mutingNotificationsMap.put(id, mutingNotifications); + notifyItemChanged(position); + } + + public void updateMutingNotificationsMap(HashMap newMutingNotificationsMap) { + mutingNotificationsMap.putAll(newMutingNotificationsMap); + notifyDataSetChanged(); + } static class MutedUserViewHolder extends RecyclerView.ViewHolder { private ImageView avatar; private TextView username; private TextView displayName; private ImageButton unmute; + private ImageButton muteNotifications; private String id; private boolean animateAvatar; + private boolean notifications; MutedUserViewHolder(View itemView) { super(itemView); @@ -65,11 +82,12 @@ public class MutesAdapter extends AccountAdapter { username = itemView.findViewById(R.id.muted_user_username); displayName = itemView.findViewById(R.id.muted_user_display_name); unmute = itemView.findViewById(R.id.muted_user_unmute); + muteNotifications = itemView.findViewById(R.id.muted_user_mute_notifications); animateAvatar = PreferenceManager.getDefaultSharedPreferences(itemView.getContext()) .getBoolean("animateGifAvatars", false); } - void setupWithAccount(Account account) { + void setupWithAccount(Account account, Boolean mutingNotifications) { id = account.getId(); CharSequence emojifiedName = CustomEmojiHelper.emojify(account.getName(), account.getEmojis(), displayName); displayName.setText(emojifiedName); @@ -79,10 +97,38 @@ public class MutesAdapter extends AccountAdapter { int avatarRadius = avatar.getContext().getResources() .getDimensionPixelSize(R.dimen.avatar_radius_48dp); ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar); + + String unmuteString = unmute.getContext().getString(R.string.action_unmute_desc, formattedUsername); + unmute.setContentDescription(unmuteString); + ViewCompat.setTooltipText(unmute, unmuteString); + + if (mutingNotifications == null) { + muteNotifications.setEnabled(false); + notifications = true; + } else { + muteNotifications.setEnabled(true); + notifications = mutingNotifications; + } + + if (notifications) { + muteNotifications.setImageResource(R.drawable.ic_notifications_24dp); + String unmuteNotificationsString = muteNotifications.getContext() + .getString(R.string.action_unmute_notifications_desc, formattedUsername); + muteNotifications.setContentDescription(unmuteNotificationsString); + ViewCompat.setTooltipText(muteNotifications, unmuteNotificationsString); + } else { + muteNotifications.setImageResource(R.drawable.ic_notifications_off_24dp); + String muteNotificationsString = muteNotifications.getContext() + .getString(R.string.action_mute_notifications_desc, formattedUsername); + muteNotifications.setContentDescription(muteNotificationsString); + ViewCompat.setTooltipText(muteNotifications, muteNotificationsString); + } } void setupActionListener(final AccountActionListener listener) { - unmute.setOnClickListener(v -> listener.onMute(false, id, getAdapterPosition())); + unmute.setOnClickListener(v -> listener.onMute(false, id, getAdapterPosition(), false)); + muteNotifications.setOnClickListener( + v -> listener.onMute(true, id, getAdapterPosition(), !notifications)); itemView.setOnClickListener(v -> listener.onViewAccount(id)); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt index aa55c99c..da2c3fb1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt @@ -193,8 +193,8 @@ class SearchViewModel @Inject constructor( return accountManager.getAllAccountsOrderedByActive() } - fun muteAccount(accountId: String) { - timelineCases.mute(accountId) + fun muteAccount(accountId: String, notifications: Boolean) { + timelineCases.mute(accountId, notifications) } fun pinAccount(status: Status, isPin: Boolean) { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt index 4e5f64fb..2a920881 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt @@ -26,6 +26,8 @@ import android.net.Uri import android.os.Environment import android.util.Log import android.view.View +import android.widget.CheckBox +import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.PopupMenu @@ -55,6 +57,7 @@ import com.keylesspalace.tusky.interfaces.StatusActionListener import com.keylesspalace.tusky.util.CardViewMode import com.keylesspalace.tusky.util.NetworkState import com.keylesspalace.tusky.util.StatusDisplayOptions +import com.keylesspalace.tusky.view.showMuteAccountDialog import com.keylesspalace.tusky.viewdata.AttachmentViewData import com.keylesspalace.tusky.viewdata.StatusViewData import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from @@ -371,11 +374,11 @@ class SearchStatusesFragment : SearchFragment viewModel.muteAccount(accountId) } - .setNegativeButton(android.R.string.cancel, null) - .show() + showMuteAccountDialog( + this.requireActivity(), + accountUsername, + { notifications -> viewModel.muteAccount(accountId, notifications) } + ) } private fun accountIsInMentions(account: AccountEntity?, mentions: Array): Boolean { diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Relationship.kt b/app/src/main/java/com/keylesspalace/tusky/entity/Relationship.kt index eb1d20b6..0c974d19 100644 --- a/app/src/main/java/com/keylesspalace/tusky/entity/Relationship.kt +++ b/app/src/main/java/com/keylesspalace/tusky/entity/Relationship.kt @@ -23,6 +23,7 @@ data class Relationship ( @SerializedName("followed_by") val followedBy: Boolean, val blocking: Boolean, val muting: Boolean, + @SerializedName("muting_notifications") val mutingNotifications: Boolean, val requested: Boolean, @SerializedName("showing_reblogs") val showingReblogs: Boolean, @SerializedName("domain_blocking") val blockingDomain: Boolean diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt index 62ba853e..9ec53b2d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt @@ -24,6 +24,7 @@ import androidx.lifecycle.Lifecycle import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.SimpleItemAnimator import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.AccountActivity import com.keylesspalace.tusky.AccountListActivity.Type @@ -48,6 +49,7 @@ import retrofit2.Call import retrofit2.Callback import retrofit2.Response import java.io.IOException +import java.util.HashMap import javax.inject.Inject @@ -80,6 +82,7 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { recyclerView.setHasFixedSize(true) val layoutManager = LinearLayoutManager(view.context) recyclerView.layoutManager = layoutManager + (recyclerView.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false recyclerView.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL)) @@ -112,50 +115,55 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { } } - override fun onMute(mute: Boolean, id: String, position: Int) { + override fun onMute(mute: Boolean, id: String, position: Int, notifications: Boolean) { val callback = object : Callback { override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { - onMuteSuccess(mute, id, position) + onMuteSuccess(mute, id, position, notifications) } else { - onMuteFailure(mute, id) + onMuteFailure(mute, id, notifications) } } override fun onFailure(call: Call, t: Throwable) { - onMuteFailure(mute, id) + onMuteFailure(mute, id, notifications) } } val call = if (!mute) { api.unmuteAccount(id) } else { - api.muteAccount(id) + api.muteAccount(id, notifications) } callList.add(call) call.enqueue(callback) } - private fun onMuteSuccess(muted: Boolean, id: String, position: Int) { + private fun onMuteSuccess(muted: Boolean, id: String, position: Int, notifications: Boolean) { + val mutesAdapter = adapter as MutesAdapter if (muted) { + mutesAdapter.updateMutingNotifications(id, notifications, position) return } - val mutesAdapter = adapter as MutesAdapter val unmutedUser = mutesAdapter.removeItem(position) if (unmutedUser != null) { Snackbar.make(recyclerView, R.string.confirmation_unmuted, Snackbar.LENGTH_LONG) .setAction(R.string.action_undo) { mutesAdapter.addItem(unmutedUser, position) - onMute(true, id, position) + onMute(true, id, position, notifications) } .show() } } - private fun onMuteFailure(mute: Boolean, accountId: String) { + private fun onMuteFailure(mute: Boolean, accountId: String, notifications: Boolean) { val verb = if (mute) { - "mute" + if (notifications) { + "mute (notifications = true)" + } else { + "mute (notifications = false)" + } } else { "unmute" } @@ -321,6 +329,10 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { adapter.update(accounts) } + if (adapter is MutesAdapter) { + fetchRelationships(accounts.map { it.id }) + } + bottomId = fromId fetching = false @@ -337,6 +349,38 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { } } + private fun fetchRelationships(ids: List) { + val callback = object : Callback> { + override fun onResponse(call: Call>, response: Response>) { + val body = response.body() + if (response.isSuccessful && body != null) { + onFetchRelationshipsSuccess(body) + } else { + onFetchRelationshipsFailure(ids) + } + } + + override fun onFailure(call: Call>, t: Throwable) { + onFetchRelationshipsFailure(ids) + } + } + + val call = api.relationships(ids) + callList.add(call) + call.enqueue(callback) + } + + private fun onFetchRelationshipsSuccess(relationships: List) { + val mutesAdapter = adapter as MutesAdapter + var mutingNotificationsMap = HashMap() + relationships.map { mutingNotificationsMap.put(it.id, it.mutingNotifications) } + mutesAdapter.updateMutingNotificationsMap(mutingNotificationsMap) + } + + private fun onFetchRelationshipsFailure(ids: List) { + Log.e(TAG, "Fetch failure for relationships of accounts: $ids") + } + private fun onFetchAccountsFailure(throwable: Throwable) { fetching = false Log.e(TAG, "Fetch failure", throwable) diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java index b94249ef..5e87c427 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java @@ -823,7 +823,7 @@ public class NotificationsFragment extends SFragment implements } @Override - public void onMute(boolean mute, String id, int position) { + public void onMute(boolean mute, String id, int position, boolean notifications) { // No muting from notifications yet } diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java index 935a02e7..3f84b3a6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java @@ -20,6 +20,7 @@ import android.app.DownloadManager; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; @@ -29,6 +30,8 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; @@ -60,6 +63,7 @@ import com.keylesspalace.tusky.entity.PollOption; import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.network.MastodonApi; import com.keylesspalace.tusky.network.TimelineCases; +import com.keylesspalace.tusky.view.MuteAccountDialog; import com.keylesspalace.tusky.viewdata.AttachmentViewData; import java.util.ArrayList; @@ -71,6 +75,8 @@ import java.util.regex.Pattern; import javax.inject.Inject; +import kotlin.Unit; + import io.reactivex.android.schedulers.AndroidSchedulers; import retrofit2.Call; import retrofit2.Callback; @@ -331,11 +337,14 @@ public abstract class SFragment extends BaseFragment implements Injectable { } private void onMute(String accountId, String accountUsername) { - new AlertDialog.Builder(requireContext()) - .setMessage(getString(R.string.dialog_mute_warning, accountUsername)) - .setPositiveButton(android.R.string.ok, (__, ___) -> timelineCases.mute(accountId)) - .setNegativeButton(android.R.string.cancel, null) - .show(); + MuteAccountDialog.showMuteAccountDialog( + this.getActivity(), + accountUsername, + (notifications) -> { + timelineCases.mute(accountId, notifications); + return Unit.INSTANCE; + } + ); } private void onBlock(String accountId, String accountUsername) { diff --git a/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.java b/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.java index 116bcae8..c353d0f3 100644 --- a/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.java +++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.java @@ -17,7 +17,7 @@ package com.keylesspalace.tusky.interfaces; public interface AccountActionListener { void onViewAccount(String id); - void onMute(final boolean mute, final String id, final int position); + void onMute(final boolean mute, final String id, final int position, final boolean notifications); void onBlock(final boolean block, final String id, final int position); void onRespondToFollowRequest(final boolean accept, final String id, final int position); } diff --git a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt index d0d78ee6..767fe257 100644 --- a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt +++ b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt @@ -317,9 +317,11 @@ interface MastodonApi { @Path("id") accountId: String ): Call + @FormUrlEncoded @POST("api/v1/accounts/{id}/mute") fun muteAccount( - @Path("id") accountId: String + @Path("id") accountId: String, + @Field("notifications") notifications: Boolean ): Call @POST("api/v1/accounts/{id}/unmute") diff --git a/app/src/main/java/com/keylesspalace/tusky/network/TimelineCases.kt b/app/src/main/java/com/keylesspalace/tusky/network/TimelineCases.kt index 50b08698..5b295f98 100644 --- a/app/src/main/java/com/keylesspalace/tusky/network/TimelineCases.kt +++ b/app/src/main/java/com/keylesspalace/tusky/network/TimelineCases.kt @@ -36,7 +36,7 @@ interface TimelineCases { fun reblog(status: Status, reblog: Boolean): Single fun favourite(status: Status, favourite: Boolean): Single fun bookmark(status: Status, bookmark: Boolean): Single - fun mute(id: String) + fun mute(id: String, notifications: Boolean) fun block(id: String) fun delete(id: String): Single fun pin(status: Status, pin: Boolean) @@ -107,8 +107,8 @@ class TimelineCasesImpl( } } - override fun mute(id: String) { - val call = mastodonApi.muteAccount(id) + override fun mute(id: String, notifications: Boolean) { + val call = mastodonApi.muteAccount(id, notifications) call.enqueue(object : Callback { override fun onResponse(call: Call, response: Response) {} diff --git a/app/src/main/java/com/keylesspalace/tusky/view/MuteAccountDialog.kt b/app/src/main/java/com/keylesspalace/tusky/view/MuteAccountDialog.kt new file mode 100644 index 00000000..2702a333 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/view/MuteAccountDialog.kt @@ -0,0 +1,27 @@ +@file:JvmName("MuteAccountDialog") + +package com.keylesspalace.tusky.view + +import android.app.Activity +import android.widget.CheckBox +import android.widget.TextView +import androidx.appcompat.app.AlertDialog +import com.keylesspalace.tusky.R + +fun showMuteAccountDialog( + activity: Activity, + accountUsername: String, + onOk: (notifications: Boolean) -> Unit +) { + val view = activity.layoutInflater.inflate(R.layout.dialog_mute_account, null) + (view.findViewById(R.id.warning) as TextView).text = + activity.getString(R.string.dialog_mute_warning, accountUsername) + val checkbox: CheckBox = view.findViewById(R.id.checkbox) + checkbox.setChecked(true) + + AlertDialog.Builder(activity) + .setView(view) + .setPositiveButton(android.R.string.ok) { _, _ -> onOk(checkbox.isChecked) } + .setNegativeButton(android.R.string.cancel, null) + .show() +} \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/viewmodel/AccountViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/viewmodel/AccountViewModel.kt index 2495fce2..bf887974 100644 --- a/app/src/main/java/com/keylesspalace/tusky/viewmodel/AccountViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/viewmodel/AccountViewModel.kt @@ -148,12 +148,12 @@ class AccountViewModel @Inject constructor( } } - fun changeMuteState() { - if (relationshipData.value?.data?.muting == true) { - changeRelationship(RelationShipAction.UNMUTE) - } else { - changeRelationship(RelationShipAction.MUTE) - } + fun muteAccount(notifications: Boolean) { + changeRelationship(RelationShipAction.MUTE, notifications) + } + + fun unmuteAccount() { + changeRelationship(RelationShipAction.UNMUTE) } fun blockDomain(instance: String) { @@ -203,7 +203,10 @@ class AccountViewModel @Inject constructor( } } - private fun changeRelationship(relationshipAction: RelationShipAction, showReblogs: Boolean = true) { + /** + * @param parameter showReblogs if RelationShipAction.FOLLOW, notifications if MUTE + */ + private fun changeRelationship(relationshipAction: RelationShipAction, parameter: Boolean? = null) { val relation = relationshipData.value?.data val account = accountData.value?.data @@ -254,11 +257,11 @@ class AccountViewModel @Inject constructor( } val call = when (relationshipAction) { - RelationShipAction.FOLLOW -> mastodonApi.followAccount(accountId, showReblogs) + RelationShipAction.FOLLOW -> mastodonApi.followAccount(accountId, parameter ?: true) RelationShipAction.UNFOLLOW -> mastodonApi.unfollowAccount(accountId) RelationShipAction.BLOCK -> mastodonApi.blockAccount(accountId) RelationShipAction.UNBLOCK -> mastodonApi.unblockAccount(accountId) - RelationShipAction.MUTE -> mastodonApi.muteAccount(accountId) + RelationShipAction.MUTE -> mastodonApi.muteAccount(accountId, parameter ?: true) RelationShipAction.UNMUTE -> mastodonApi.unmuteAccount(accountId) } diff --git a/app/src/main/res/drawable/ic_notifications_off_24dp.xml b/app/src/main/res/drawable/ic_notifications_off_24dp.xml new file mode 100644 index 00000000..627eafd2 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_off_24dp.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_mute_account.xml b/app/src/main/res/layout/dialog_mute_account.xml new file mode 100644 index 00000000..673fc9e4 --- /dev/null +++ b/app/src/main/res/layout/dialog_mute_account.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_muted_user.xml b/app/src/main/res/layout/item_muted_user.xml index 3ef7ab18..fc9a11d8 100644 --- a/app/src/main/res/layout/item_muted_user.xml +++ b/app/src/main/res/layout/item_muted_user.xml @@ -22,14 +22,26 @@ style="@style/TuskyImageButton" android:layout_width="32dp" android:layout_height="32dp" + android:layout_toStartOf="@id/muted_user_mute_notifications" + android:layout_centerVertical="true" + android:layout_gravity="center_vertical" + android:layout_marginStart="12dp" + android:background="?attr/selectableItemBackgroundBorderless" + android:padding="4dp" + app:srcCompat="@drawable/ic_unmute_24dp" /> + + + app:srcCompat="@drawable/ic_notifications_24dp" /> Share Mute Unmute + Unmute %s + Unmute notifications from %s + Mute notifications from %s Mute %s Unmute %s Mute conversation @@ -199,6 +202,7 @@ Hide entire domain Block @%s? Mute @%s? + Hide notifications Public: Post to public timelines Unlisted: Do not show in public timelines