diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt index de987818a1..daade299eb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt @@ -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())) } ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkDialogFragment.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkDialogFragment.java deleted file mode 100644 index 48d20b1d24..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkDialogFragment.java +++ /dev/null @@ -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); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkFragment.kt new file mode 100644 index 0000000000..695c5f15ea --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkFragment.kt @@ -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) + } +} diff --git a/app/src/main/res/layout/group_invite_link_enable_and_share_bottom_sheet.xml b/app/src/main/res/layout/group_invite_link_enable_and_share_bottom_sheet.xml index e2457f9817..af107e48f5 100644 --- a/app/src/main/res/layout/group_invite_link_enable_and_share_bottom_sheet.xml +++ b/app/src/main/res/layout/group_invite_link_enable_and_share_bottom_sheet.xml @@ -68,11 +68,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:clickable="false" - app:layout_constraintBottom_toBottomOf="@id/shareable_group_link_enable_label" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toEndOf="@id/shareable_group_link_enable_label" - app:layout_constraintTop_toTopOf="@id/shareable_group_link_enable_label" /> + android:clickable="false" /> diff --git a/app/src/main/res/layout/shareable_group_link_dialog_fragment.xml b/app/src/main/res/layout/shareable_group_link_dialog_fragment.xml deleted file mode 100644 index 73633513ab..0000000000 --- a/app/src/main/res/layout/shareable_group_link_dialog_fragment.xml +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/conversation_settings.xml b/app/src/main/res/navigation/conversation_settings.xml index 0bbb2c3bd5..f73195bba0 100644 --- a/app/src/main/res/navigation/conversation_settings.xml +++ b/app/src/main/res/navigation/conversation_settings.xml @@ -33,8 +33,8 @@ + app:argType="java.lang.Integer" + app:nullable="true" /> + + + + + + + + \ No newline at end of file