Add group link join version feature flag.

master
Alan Evans 2020-08-25 16:35:06 -03:00 committed by GitHub
parent f18b653725
commit 92ecf2d5de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 127 additions and 12 deletions

View File

@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
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;
@ -91,15 +92,27 @@ public final class GroupJoinBottomSheetDialogFragment extends BottomSheetDialogF
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);
});

View File

@ -4,6 +4,8 @@ import android.os.Bundle;
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;
@ -14,11 +16,16 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
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);
}
@ -34,18 +41,37 @@ public final class GroupJoinUpdateRequiredBottomSheetDialogFragment extends Bott
@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

View File

@ -184,8 +184,12 @@ public class CommunicationActions {
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;
}

View File

@ -10,6 +10,7 @@ import com.google.android.collect.Sets;
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;
@ -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";
@ -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
);
@ -222,6 +225,30 @@ public final class FeatureFlags {
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);

View File

@ -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"

View File

@ -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 youre 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>

View File

@ -64,6 +64,20 @@ public class FeatureFlagsTest extends BaseUnitTest {
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),
@ -106,6 +120,20 @@ public class FeatureFlagsTest extends BaseUnitTest {
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),
@ -120,6 +148,20 @@ public class FeatureFlagsTest extends BaseUnitTest {
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),