Refactor ShareableGroupLinkDialogFragment into a normal Fragment.

Co-authored-by: Rashad Sookram <rashad@signal.org>
This commit is contained in:
Alex Hart
2021-12-14 13:03:47 -04:00
committed by Greyson Parrelli
parent 20d2c43356
commit 68bd9c6e1e
6 changed files with 154 additions and 401 deletions

View File

@@ -74,7 +74,6 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientExporter
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.recipients.ui.bottomsheet.RecipientBottomSheetDialogFragment
import org.thoughtcrime.securesms.recipients.ui.sharablegrouplink.ShareableGroupLinkDialogFragment
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.ContextUtil
import org.thoughtcrime.securesms.util.ExpirationUtil
@@ -615,7 +614,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
summary = DSLSettingsText.from(if (groupState.groupLinkEnabled) R.string.preferences_on else R.string.preferences_off),
icon = DSLSettingsIcon.from(R.drawable.ic_link_16),
onClick = {
ShareableGroupLinkDialogFragment.create(groupState.groupId.requireV2()).show(parentFragmentManager, "DIALOG")
navController.navigate(ConversationSettingsFragmentDirections.actionConversationSettingsFragmentToShareableGroupLinkFragment(groupState.groupId.requireV2().toString()))
}
)

View File

@@ -1,157 +0,0 @@
package org.thoughtcrime.securesms.recipients.ui.sharablegrouplink;
import android.app.AlertDialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProviders;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
public final class ShareableGroupLinkDialogFragment extends DialogFragment {
private static final String ARG_GROUP_ID = "group_id";
private ShareableGroupLinkViewModel viewModel;
private GroupId.V2 groupId;
private SimpleProgressDialog.DismissibleDialog dialog;
public static DialogFragment create(@NonNull GroupId.V2 groupId) {
DialogFragment fragment = new ShareableGroupLinkDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_GROUP_ID, groupId.toString());
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_Animated);
}
@Override
public @Nullable View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
return inflater.inflate(R.layout.shareable_group_link_dialog_fragment, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
initializeViewModel();
initializeViews(view);
}
private void initializeViewModel() {
//noinspection ConstantConditions
groupId = GroupId.parseOrThrow(requireArguments().getString(ARG_GROUP_ID)).requireV2();
ShareableGroupLinkRepository repository = new ShareableGroupLinkRepository(requireContext(), groupId);
ShareableGroupLinkViewModel.Factory factory = new ShareableGroupLinkViewModel.Factory(groupId, repository);
viewModel = ViewModelProviders.of(this, factory).get(ShareableGroupLinkViewModel.class);
}
private void initializeViews(@NonNull View view) {
SwitchCompat shareableGroupLinkSwitch = view.findViewById(R.id.shareable_group_link_enable_switch);
TextView shareableGroupLinkDisplay = view.findViewById(R.id.shareable_group_link_display);
View shareableGroupLinkDisplayRow = view.findViewById(R.id.shareable_group_link_display_row);
SwitchCompat approveNewMembersSwitch = view.findViewById(R.id.shareable_group_link_approve_new_members_switch);
View shareableGroupLinkRow = view.findViewById(R.id.shareable_group_link_row);
View shareRow = view.findViewById(R.id.shareable_group_link_share_row);
View resetLinkRow = view.findViewById(R.id.shareable_group_link_reset_link_row);
View approveNewMembersRow = view.findViewById(R.id.shareable_group_link_approve_new_members_row);
View membersSectionHeader = view.findViewById(R.id.shareable_group_link_member_requests_section_header);
View descriptionRow = view.findViewById(R.id.shareable_group_link_display_row2);
Toolbar toolbar = view.findViewById(R.id.shareable_group_link_toolbar);
toolbar.setNavigationOnClickListener(v -> dismissAllowingStateLoss());
viewModel.getGroupLink().observe(getViewLifecycleOwner(), groupLink -> {
shareableGroupLinkSwitch.setChecked(groupLink.isEnabled());
approveNewMembersSwitch.setChecked(groupLink.isRequiresApproval());
shareableGroupLinkDisplay.setText(formatForFullWidthWrapping(groupLink.getUrl()));
shareableGroupLinkDisplayRow.setVisibility(groupLink.isEnabled() ? View.VISIBLE : View.GONE);
ViewUtil.setEnabledRecursive(shareRow, groupLink.isEnabled());
ViewUtil.setEnabledRecursive(resetLinkRow, groupLink.isEnabled());
ViewUtil.setEnabledRecursive(membersSectionHeader, groupLink.isEnabled());
ViewUtil.setEnabledRecursive(approveNewMembersRow, groupLink.isEnabled());
ViewUtil.setEnabledRecursive(descriptionRow, groupLink.isEnabled());
});
shareRow.setOnClickListener(v -> GroupLinkBottomSheetDialogFragment.show(requireFragmentManager(), groupId));
viewModel.getCanEdit().observe(getViewLifecycleOwner(), canEdit -> {
if (canEdit) {
shareableGroupLinkRow.setOnClickListener(v -> viewModel.onToggleGroupLink());
approveNewMembersRow.setOnClickListener(v -> viewModel.onToggleApproveMembers());
resetLinkRow.setOnClickListener(v -> onResetGroupLink());
} else {
shareableGroupLinkRow.setOnClickListener(v -> toast(R.string.ManageGroupActivity_only_admins_can_enable_or_disable_the_sharable_group_link));
approveNewMembersRow.setOnClickListener(v -> toast(R.string.ManageGroupActivity_only_admins_can_enable_or_disable_the_option_to_approve_new_members));
resetLinkRow.setOnClickListener(v -> toast(R.string.ManageGroupActivity_only_admins_can_reset_the_sharable_group_link));
}
});
viewModel.getToasts().observe(getViewLifecycleOwner(), this::toast);
viewModel.getBusy().observe(getViewLifecycleOwner(), busy -> {
if (busy) {
if (dialog == null) {
dialog = SimpleProgressDialog.showDelayed(requireContext());
}
} else {
if (dialog != null) {
dialog.dismiss();
dialog = null;
}
}
});
}
private void onResetGroupLink() {
new AlertDialog.Builder(requireContext())
.setMessage(R.string.ShareableGroupLinkDialogFragment__are_you_sure_you_want_to_reset_the_group_link)
.setPositiveButton(R.string.ShareableGroupLinkDialogFragment__reset_link, (dialog, which) -> viewModel.onResetLink())
.setNegativeButton(android.R.string.cancel, null)
.show();
}
protected void toast(@StringRes int message) {
Toast.makeText(requireContext(), getString(message), Toast.LENGTH_SHORT).show();
}
/**
* Inserts zero width space characters between each character in the original ensuring it takes
* the full width of the TextView.
*/
private static CharSequence formatForFullWidthWrapping(@NonNull String url) {
char[] chars = new char[url.length() * 2];
for (int i = 0; i < url.length(); i++) {
chars[i * 2] = url.charAt(i);
chars[i * 2 + 1] = '\u200B';
}
return new String(chars);
}
}

View File

@@ -0,0 +1,132 @@
package org.thoughtcrime.securesms.recipients.ui.sharablegrouplink
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.fragment.app.viewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.groups.v2.GroupLinkUrlAndStatus
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog
/**
* Fragment providing user options to manage group links.
*/
class ShareableGroupLinkFragment : DSLSettingsFragment(
titleId = R.string.ShareableGroupLinkDialogFragment__group_link
) {
private var busyDialog: SimpleProgressDialog.DismissibleDialog? = null
private val groupId: GroupId.V2
get() = GroupId.parseOrThrow(ShareableGroupLinkFragmentArgs.fromBundle(requireArguments()).groupId).requireV2()
private val viewModel: ShareableGroupLinkViewModel by viewModels(
factoryProducer = {
val repository = ShareableGroupLinkRepository(requireContext(), groupId)
ShareableGroupLinkViewModel.Factory(groupId, repository)
}
)
override fun bindAdapter(adapter: DSLSettingsAdapter) {
LiveDataUtil.combineLatest(viewModel.groupLink, viewModel.canEdit) { groupLink, canEdit ->
Pair(groupLink, canEdit)
}.observe(viewLifecycleOwner) { (groupLink, canEdit) ->
adapter.submitList(getConfiguration(groupLink, canEdit).toMappingModelList())
}
viewModel.toasts.observe(viewLifecycleOwner, this::toast)
viewModel.busy.observe(
viewLifecycleOwner,
{ busy ->
if (busy) {
if (busyDialog == null) {
busyDialog = SimpleProgressDialog.showDelayed(requireContext())
}
} else {
busyDialog?.dismiss()
busyDialog = null
}
}
)
}
private fun toast(@StringRes message: Int) {
Toast.makeText(requireContext(), getString(message), Toast.LENGTH_SHORT).show()
}
private fun getConfiguration(groupLink: GroupLinkUrlAndStatus, canEdit: Boolean): DSLConfiguration {
return configure {
switchPref(
title = DSLSettingsText.from(R.string.ShareableGroupLinkDialogFragment__group_link),
summary = if (groupLink.isEnabled) DSLSettingsText.from(formatForFullWidthWrapping(groupLink.url)) else null,
isChecked = groupLink.isEnabled,
isEnabled = canEdit,
onClick = {
viewModel.onToggleGroupLink()
}
)
clickPref(
title = DSLSettingsText.from(R.string.ShareableGroupLinkDialogFragment__share),
icon = DSLSettingsIcon.from(R.drawable.ic_share_24_tinted),
isEnabled = groupLink.isEnabled,
onClick = {
GroupLinkBottomSheetDialogFragment.show(childFragmentManager, groupId)
}
)
clickPref(
title = DSLSettingsText.from(R.string.ShareableGroupLinkDialogFragment__reset_link),
icon = DSLSettingsIcon.from(R.drawable.ic_reset_24_tinted),
isEnabled = groupLink.isEnabled && canEdit,
onClick = {
onResetGroupLink()
}
)
dividerPref()
switchPref(
title = DSLSettingsText.from(R.string.ShareableGroupLinkDialogFragment__approve_new_members),
summary = DSLSettingsText.from(R.string.ShareableGroupLinkDialogFragment__require_an_admin_to_approve_new_members_joining_via_the_group_link),
isEnabled = groupLink.isEnabled && canEdit,
isChecked = groupLink.isRequiresApproval,
onClick = {
viewModel.onToggleApproveMembers()
}
)
}
}
private fun onResetGroupLink() {
MaterialAlertDialogBuilder(requireContext())
.setMessage(R.string.ShareableGroupLinkDialogFragment__are_you_sure_you_want_to_reset_the_group_link)
.setPositiveButton(R.string.ShareableGroupLinkDialogFragment__reset_link) { _, _ -> viewModel.onResetLink() }
.setNegativeButton(android.R.string.cancel, null)
.show()
}
/**
* Inserts zero width space characters between each character in the original ensuring it takes
* the full width of the TextView.
*/
private fun formatForFullWidthWrapping(url: String): CharSequence {
val chars = CharArray(url.length * 2)
for (i in url.indices) {
chars[i * 2] = url[i]
chars[i * 2 + 1] = '\u200B'
}
return String(chars)
}
}