Skip to content

Commit

Permalink
Add group link join version feature flag.
Browse files Browse the repository at this point in the history
  • Loading branch information
alan-signal committed Aug 25, 2020
1 parent f18b653 commit 92ecf2d
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.BottomSheetUtil;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.PlayStoreUtil;
import org.thoughtcrime.securesms.util.ThemeUtil;

Expand Down Expand Up @@ -91,15 +92,27 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
viewModel.getGroupDetails().observe(getViewLifecycleOwner(), details -> {
groupName.setText(details.getGroupName());
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 -> {
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
dismiss();
});
groupJoinExplain.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_update_message);

switch (FeatureFlags.clientLocalGroupJoinStatus()) {
case COMING_SOON:
groupJoinExplain.setText(R.string.GroupJoinUpdateRequiredBottomSheetDialogFragment_coming_soon);
groupCancelButton.setText(android.R.string.ok);
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);

groupJoinButton.setVisibility(View.VISIBLE);
groupCancelButton.setVisibility(View.VISIBLE);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand All @@ -14,11 +16,16 @@

import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.BottomSheetUtil;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.PlayStoreUtil;
import org.thoughtcrime.securesms.util.ThemeUtil;

public final class GroupJoinUpdateRequiredBottomSheetDialogFragment extends BottomSheetDialogFragment {

private TextView groupJoinTitle;
private TextView groupJoinExplain;
private Button groupJoinButton;

public static void show(@NonNull FragmentManager manager) {
new GroupJoinUpdateRequiredBottomSheetDialogFragment().show(manager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
}
Expand All @@ -34,18 +41,37 @@ public void onCreate(@Nullable Bundle savedInstanceState) {

@Override
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
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);

view.findViewById(R.id.group_join_update_button)
.setOnClickListener(v -> {
switch (FeatureFlags.clientLocalGroupJoinStatus()) {
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());
dismiss();
});
break;
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,12 @@ public static boolean handlePotentialGroupLinkUrl(@NonNull FragmentActivity acti

handleGroupLinkUrl(activity, groupInviteLinkUrl);
return true;
} catch (GroupInviteLinkUrl.InvalidGroupLinkException | GroupInviteLinkUrl.UnknownGroupLinkVersionException e) {
} catch (GroupInviteLinkUrl.InvalidGroupLinkException 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());
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import org.json.JSONException;
import org.json.JSONObject;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
Expand Down Expand Up @@ -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 = "android.groupsv2.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 CDS = "android.cds.4";
private static final String INTERNAL_USER = "android.internalUser";
Expand Down Expand Up @@ -98,6 +100,7 @@ public final class FeatureFlags {
private static final Set<String> HOT_SWAPPABLE = Sets.newHashSet(
ATTACHMENTS_V3,
GROUPS_V2_CREATE,
GROUPS_V2_JOIN_VERSION,
VERIFY_V2,
CDS
);
Expand Down Expand Up @@ -222,6 +225,30 @@ public static int gv2GroupCapacity() {
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. */
public static boolean internalUser() {
return getBoolean(INTERNAL_USER, false);
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/layout/group_join_bottom_sheet.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:text="@android:string/cancel"
android:visibility="gone"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/group_join_button"
app:layout_constraintHorizontal_bias="0.5"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -660,9 +660,12 @@
</plurals>

<!-- 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_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_signal">Update Signal</string>
<string name="GroupJoinUpdateRequiredBottomSheetDialogFragment_group_link_is_not_valid">Group link is not valid</string>

<!-- CropImageActivity -->
<string name="CropImageActivity_group_avatar">Group avatar</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ public void updateInternal_newValue_hotSwap() {
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
public void updateInternal_newValue_sticky() {
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, true),
Expand Down Expand Up @@ -106,6 +120,20 @@ public void updateInternal_replaceValue() {
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
public void updateInternal_replaceValue_hotSwap() {
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, true),
Expand All @@ -120,6 +148,20 @@ public void updateInternal_replaceValue_hotSwap() {
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
public void updateInternal_replaceValue_hotSwap_stickyChange() {
UpdateResult result = FeatureFlags.updateInternal(mapOf(A, true),
Expand Down

0 comments on commit 92ecf2d

Please sign in to comment.