Add group link join version feature flag.
This commit is contained in:
parent
f18b653725
commit
92ecf2d5de
7 changed files with 127 additions and 12 deletions
|
@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
|
||||||
import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl;
|
import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.BottomSheetUtil;
|
import org.thoughtcrime.securesms.util.BottomSheetUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.PlayStoreUtil;
|
import org.thoughtcrime.securesms.util.PlayStoreUtil;
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
|
|
||||||
|
@ -91,15 +92,27 @@ public final class GroupJoinBottomSheetDialogFragment extends BottomSheetDialogF
|
||||||
viewModel.getGroupDetails().observe(getViewLifecycleOwner(), details -> {
|
viewModel.getGroupDetails().observe(getViewLifecycleOwner(), details -> {
|
||||||
groupName.setText(details.getGroupName());
|
groupName.setText(details.getGroupName());
|
||||||
groupDetails.setText(requireContext().getResources().getQuantityString(R.plurals.GroupJoinBottomSheetDialogFragment_group_dot_d_members, details.getGroupMembershipCount(), details.getGroupMembershipCount()));
|
groupDetails.setText(requireContext().getResources().getQuantityString(R.plurals.GroupJoinBottomSheetDialogFragment_group_dot_d_members, details.getGroupMembershipCount(), details.getGroupMembershipCount()));
|
||||||
groupJoinButton.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_update_signal);
|
|
||||||
groupJoinButton.setOnClickListener(v -> {
|
switch (FeatureFlags.clientLocalGroupJoinStatus()) {
|
||||||
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
|
case COMING_SOON:
|
||||||
dismiss();
|
groupJoinExplain.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_coming_soon);
|
||||||
});
|
groupCancelButton.setText(android.R.string.ok);
|
||||||
groupJoinExplain.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_update_message);
|
groupJoinButton.setVisibility(View.GONE);
|
||||||
|
break;
|
||||||
|
case UPDATE_TO_JOIN:
|
||||||
|
case LOCAL_CAN_JOIN:
|
||||||
|
groupJoinExplain.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_update_message);
|
||||||
|
groupJoinButton.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_update_signal);
|
||||||
|
groupJoinButton.setOnClickListener(v -> {
|
||||||
|
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
|
||||||
|
dismiss();
|
||||||
|
});
|
||||||
|
groupJoinButton.setVisibility(View.VISIBLE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
avatar.setImageBytesForGroup(details.getAvatarBytes(), new FallbackPhotoProvider(), MaterialColor.STEEL);
|
avatar.setImageBytesForGroup(details.getAvatarBytes(), new FallbackPhotoProvider(), MaterialColor.STEEL);
|
||||||
|
|
||||||
groupJoinButton.setVisibility(View.VISIBLE);
|
|
||||||
groupCancelButton.setVisibility(View.VISIBLE);
|
groupCancelButton.setVisibility(View.VISIBLE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -14,11 +16,16 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.util.BottomSheetUtil;
|
import org.thoughtcrime.securesms.util.BottomSheetUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.PlayStoreUtil;
|
import org.thoughtcrime.securesms.util.PlayStoreUtil;
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
|
|
||||||
public final class GroupJoinUpdateRequiredBottomSheetDialogFragment extends BottomSheetDialogFragment {
|
public final class GroupJoinUpdateRequiredBottomSheetDialogFragment extends BottomSheetDialogFragment {
|
||||||
|
|
||||||
|
private TextView groupJoinTitle;
|
||||||
|
private TextView groupJoinExplain;
|
||||||
|
private Button groupJoinButton;
|
||||||
|
|
||||||
public static void show(@NonNull FragmentManager manager) {
|
public static void show(@NonNull FragmentManager manager) {
|
||||||
new GroupJoinUpdateRequiredBottomSheetDialogFragment().show(manager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
|
new GroupJoinUpdateRequiredBottomSheetDialogFragment().show(manager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
|
||||||
}
|
}
|
||||||
|
@ -34,18 +41,37 @@ public final class GroupJoinUpdateRequiredBottomSheetDialogFragment extends Bott
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
return inflater.inflate(R.layout.group_join_update_needed_bottom_sheet, container, false);
|
View view = inflater.inflate(R.layout.group_join_update_needed_bottom_sheet, container, false);
|
||||||
|
|
||||||
|
groupJoinTitle = view.findViewById(R.id.group_join_update_title);
|
||||||
|
groupJoinButton = view.findViewById(R.id.group_join_update_button);
|
||||||
|
groupJoinExplain = view.findViewById(R.id.group_join_update_explain);
|
||||||
|
|
||||||
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
view.findViewById(R.id.group_join_update_button)
|
switch (FeatureFlags.clientLocalGroupJoinStatus()) {
|
||||||
.setOnClickListener(v -> {
|
case COMING_SOON:
|
||||||
|
groupJoinTitle.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_group_links_coming_soon);
|
||||||
|
groupJoinExplain.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_coming_soon);
|
||||||
|
groupJoinButton.setText(android.R.string.ok);
|
||||||
|
groupJoinButton.setOnClickListener(v -> dismiss());
|
||||||
|
break;
|
||||||
|
case UPDATE_TO_JOIN:
|
||||||
|
case LOCAL_CAN_JOIN:
|
||||||
|
groupJoinTitle.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_update_signal_to_use_group_links);
|
||||||
|
groupJoinExplain.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_update_message);
|
||||||
|
groupJoinButton.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_update_signal);
|
||||||
|
groupJoinButton.setOnClickListener(v -> {
|
||||||
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
|
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
|
||||||
dismiss();
|
dismiss();
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -184,8 +184,12 @@ public class CommunicationActions {
|
||||||
|
|
||||||
handleGroupLinkUrl(activity, groupInviteLinkUrl);
|
handleGroupLinkUrl(activity, groupInviteLinkUrl);
|
||||||
return true;
|
return true;
|
||||||
} catch (GroupInviteLinkUrl.InvalidGroupLinkException | GroupInviteLinkUrl.UnknownGroupLinkVersionException e) {
|
} catch (GroupInviteLinkUrl.InvalidGroupLinkException e) {
|
||||||
Log.w(TAG, "Could not parse group URL", e);
|
Log.w(TAG, "Could not parse group URL", e);
|
||||||
|
Toast.makeText(activity, R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_group_link_is_not_valid, Toast.LENGTH_SHORT).show();
|
||||||
|
return true;
|
||||||
|
} catch (GroupInviteLinkUrl.UnknownGroupLinkVersionException e) {
|
||||||
|
Log.w(TAG, "Group link is for an advanced version", e);
|
||||||
GroupJoinUpdateRequiredBottomSheetDialogFragment.show(activity.getSupportFragmentManager());
|
GroupJoinUpdateRequiredBottomSheetDialogFragment.show(activity.getSupportFragmentManager());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import com.google.android.collect.Sets;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
import org.thoughtcrime.securesms.BuildConfig;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
|
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
|
||||||
|
@ -55,6 +56,7 @@ public final class FeatureFlags {
|
||||||
private static final String GROUPS_V2_OLD_2 = "android.groupsv2.2";
|
private static final String GROUPS_V2_OLD_2 = "android.groupsv2.2";
|
||||||
private static final String GROUPS_V2 = "android.groupsv2.3";
|
private static final String GROUPS_V2 = "android.groupsv2.3";
|
||||||
private static final String GROUPS_V2_CREATE = "android.groupsv2.create.3";
|
private static final String GROUPS_V2_CREATE = "android.groupsv2.create.3";
|
||||||
|
private static final String GROUPS_V2_JOIN_VERSION = "android.groupsv2.joinVersion";
|
||||||
private static final String GROUPS_V2_CAPACITY = "global.groupsv2.maxGroupSize";
|
private static final String GROUPS_V2_CAPACITY = "global.groupsv2.maxGroupSize";
|
||||||
private static final String CDS = "android.cds.4";
|
private static final String CDS = "android.cds.4";
|
||||||
private static final String INTERNAL_USER = "android.internalUser";
|
private static final String INTERNAL_USER = "android.internalUser";
|
||||||
|
@ -98,6 +100,7 @@ public final class FeatureFlags {
|
||||||
private static final Set<String> HOT_SWAPPABLE = Sets.newHashSet(
|
private static final Set<String> HOT_SWAPPABLE = Sets.newHashSet(
|
||||||
ATTACHMENTS_V3,
|
ATTACHMENTS_V3,
|
||||||
GROUPS_V2_CREATE,
|
GROUPS_V2_CREATE,
|
||||||
|
GROUPS_V2_JOIN_VERSION,
|
||||||
VERIFY_V2,
|
VERIFY_V2,
|
||||||
CDS
|
CDS
|
||||||
);
|
);
|
||||||
|
@ -222,6 +225,30 @@ public final class FeatureFlags {
|
||||||
return getInteger(GROUPS_V2_CAPACITY, 151);
|
return getInteger(GROUPS_V2_CAPACITY, 151);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ability of local client to join a GV2 group.
|
||||||
|
* <p>
|
||||||
|
* You must still check GV2 capabilities to respect linked devices.
|
||||||
|
*/
|
||||||
|
public static GroupJoinStatus clientLocalGroupJoinStatus() {
|
||||||
|
int groupJoinVersion = getInteger(GROUPS_V2_JOIN_VERSION, 0);
|
||||||
|
|
||||||
|
if (groupJoinVersion == 0) return GroupJoinStatus.COMING_SOON;
|
||||||
|
else if (groupJoinVersion > BuildConfig.CANONICAL_VERSION_CODE) return GroupJoinStatus.UPDATE_TO_JOIN;
|
||||||
|
else return GroupJoinStatus.LOCAL_CAN_JOIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum GroupJoinStatus {
|
||||||
|
/** No version of the client that can join V2 groups by link is in production. */
|
||||||
|
COMING_SOON,
|
||||||
|
|
||||||
|
/** A newer version of the client is in production that will allow joining via GV2 group links. */
|
||||||
|
UPDATE_TO_JOIN,
|
||||||
|
|
||||||
|
/** This version of the client allows joining via GV2 group links. */
|
||||||
|
LOCAL_CAN_JOIN
|
||||||
|
}
|
||||||
|
|
||||||
/** Internal testing extensions. */
|
/** Internal testing extensions. */
|
||||||
public static boolean internalUser() {
|
public static boolean internalUser() {
|
||||||
return getBoolean(INTERNAL_USER, false);
|
return getBoolean(INTERNAL_USER, false);
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:text="@android:string/cancel"
|
android:text="@android:string/cancel"
|
||||||
android:visibility="gone"
|
android:visibility="invisible"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/group_join_button"
|
app:layout_constraintEnd_toStartOf="@+id/group_join_button"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
|
|
@ -660,9 +660,12 @@
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
<!-- GroupJoinUpdateRequiredBottomSheetDialogFragment -->
|
<!-- GroupJoinUpdateRequiredBottomSheetDialogFragment -->
|
||||||
|
<string name="GroupJoinUpdateRequiredBottomSheetDialogFragment_group_links_coming_soon">Group links coming soon</string>
|
||||||
<string name="GroupJoinUpdateRequiredBottomSheetDialogFragment_update_signal_to_use_group_links">Update Signal to use group links</string>
|
<string name="GroupJoinUpdateRequiredBottomSheetDialogFragment_update_signal_to_use_group_links">Update Signal to use group links</string>
|
||||||
|
<string name="GroupJoinUpdateRequiredBottomSheetDialogFragment_coming_soon">Joining a group via a link is not yet supported by Signal. This feature will be released in an upcoming update.</string>
|
||||||
<string name="GroupJoinUpdateRequiredBottomSheetDialogFragment_update_message">The version of Signal you’re using does not support sharable group links. Update to the latest version to join this group via link.</string>
|
<string name="GroupJoinUpdateRequiredBottomSheetDialogFragment_update_message">The version of Signal you’re using does not support sharable group links. Update to the latest version to join this group via link.</string>
|
||||||
<string name="GroupJoinUpdateRequiredBottomSheetDialogFragment_update_signal">Update Signal</string>
|
<string name="GroupJoinUpdateRequiredBottomSheetDialogFragment_update_signal">Update Signal</string>
|
||||||
|
<string name="GroupJoinUpdateRequiredBottomSheetDialogFragment_group_link_is_not_valid">Group link is not valid</string>
|
||||||
|
|
||||||
<!-- CropImageActivity -->
|
<!-- CropImageActivity -->
|
||||||
<string name="CropImageActivity_group_avatar">Group avatar</string>
|
<string name="CropImageActivity_group_avatar">Group avatar</string>
|
||||||
|
|
|
@ -64,6 +64,20 @@ public class FeatureFlagsTest extends BaseUnitTest {
|
||||||
assertEquals(Change.ENABLED, result.getMemoryChanges().get(A));
|
assertEquals(Change.ENABLED, result.getMemoryChanges().get(A));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateInternal_newValue_hotSwap_integer() {
|
||||||
|
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, 1),
|
||||||
|
mapOf(),
|
||||||
|
mapOf(),
|
||||||
|
setOf(A),
|
||||||
|
setOf(A),
|
||||||
|
setOf());
|
||||||
|
|
||||||
|
assertEquals(mapOf(A, 1), result.getMemory());
|
||||||
|
assertEquals(mapOf(A, 1), result.getDisk());
|
||||||
|
assertEquals(Change.CHANGED, result.getMemoryChanges().get(A));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateInternal_newValue_sticky() {
|
public void updateInternal_newValue_sticky() {
|
||||||
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, true),
|
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, true),
|
||||||
|
@ -106,6 +120,20 @@ public class FeatureFlagsTest extends BaseUnitTest {
|
||||||
assertTrue(result.getMemoryChanges().isEmpty());
|
assertTrue(result.getMemoryChanges().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateInternal_replaceValue_integer() {
|
||||||
|
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, 2),
|
||||||
|
mapOf(A, 1),
|
||||||
|
mapOf(A, 1),
|
||||||
|
setOf(A),
|
||||||
|
setOf(),
|
||||||
|
setOf());
|
||||||
|
|
||||||
|
assertEquals(mapOf(A, 1), result.getMemory());
|
||||||
|
assertEquals(mapOf(A, 2), result.getDisk());
|
||||||
|
assertTrue(result.getMemoryChanges().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateInternal_replaceValue_hotSwap() {
|
public void updateInternal_replaceValue_hotSwap() {
|
||||||
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, true),
|
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, true),
|
||||||
|
@ -120,6 +148,20 @@ public class FeatureFlagsTest extends BaseUnitTest {
|
||||||
assertEquals(Change.ENABLED, result.getMemoryChanges().get(A));
|
assertEquals(Change.ENABLED, result.getMemoryChanges().get(A));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateInternal_replaceValue_hotSwa_integer() {
|
||||||
|
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, 2),
|
||||||
|
mapOf(A, 1),
|
||||||
|
mapOf(A, 1),
|
||||||
|
setOf(A),
|
||||||
|
setOf(A),
|
||||||
|
setOf());
|
||||||
|
|
||||||
|
assertEquals(mapOf(A, 2), result.getMemory());
|
||||||
|
assertEquals(mapOf(A, 2), result.getDisk());
|
||||||
|
assertEquals(Change.CHANGED, result.getMemoryChanges().get(A));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateInternal_replaceValue_hotSwap_stickyChange() {
|
public void updateInternal_replaceValue_hotSwap_stickyChange() {
|
||||||
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, true),
|
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, true),
|
||||||
|
|
Loading…
Add table
Reference in a new issue