Signal-Android/app/src/main/java/org/thoughtcrime/securesms/insights/InsightsDashboardDialogFrag...

272 wiersze
10 KiB
Java

package org.thoughtcrime.securesms.insights;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.content.Intent;
import android.content.res.Configuration;
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;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
import com.airbnb.lottie.LottieAnimationView;
import org.thoughtcrime.securesms.NewConversationActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.ArcProgressBar;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.ThemeUtil;
import java.util.List;
public final class InsightsDashboardDialogFragment extends DialogFragment {
private TextView securePercentage;
private ArcProgressBar progress;
private View progressContainer;
private TextView tagline;
private TextView encryptedMessages;
private TextView title;
private TextView description;
private RecyclerView insecureRecipients;
private TextView locallyGenerated;
private AvatarImageView avatarImageView;
private InsightsInsecureRecipientsAdapter adapter;
private LottieAnimationView lottieAnimationView;
private AnimatorSet animatorSet;
private Button startAConversation;
private Toolbar toolbar;
private InsightsDashboardViewModel viewModel;
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
requireFragmentManager().beginTransaction()
.detach(this)
.attach(this)
.commit();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (ThemeUtil.isDarkTheme(requireActivity())) {
setStyle(STYLE_NO_FRAME, R.style.TextSecure_DarkTheme);
} else {
setStyle(STYLE_NO_FRAME, R.style.TextSecure_LightTheme);
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.insights_dashboard, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
securePercentage = view.findViewById(R.id.insights_dashboard_percent_secure);
progress = view.findViewById(R.id.insights_dashboard_progress);
progressContainer = view.findViewById(R.id.insights_dashboard_percent_container);
encryptedMessages = view.findViewById(R.id.insights_dashboard_encrypted_messages);
tagline = view.findViewById(R.id.insights_dashboard_tagline);
title = view.findViewById(R.id.insights_dashboard_make_signal_secure);
description = view.findViewById(R.id.insights_dashboard_invite_your_contacts);
insecureRecipients = view.findViewById(R.id.insights_dashboard_recycler);
locallyGenerated = view.findViewById(R.id.insights_dashboard_this_stat_was_generated_locally);
avatarImageView = view.findViewById(R.id.insights_dashboard_avatar);
startAConversation = view.findViewById(R.id.insights_dashboard_start_a_conversation);
lottieAnimationView = view.findViewById(R.id.insights_dashboard_lottie_animation);
toolbar = view.findViewById(R.id.insights_dashboard_toolbar);
setupStartAConversation();
setDashboardDetailsAlpha(0f);
setNotEnoughDataAlpha(0f);
setupToolbar();
setupRecycler();
initializeViewModel();
}
private void setupStartAConversation() {
startAConversation.setOnClickListener(v -> startActivity(new Intent(requireActivity(), NewConversationActivity.class)));
}
private void setDashboardDetailsAlpha(float alpha) {
tagline.setAlpha(alpha);
title.setAlpha(alpha);
description.setAlpha(alpha);
insecureRecipients.setAlpha(alpha);
locallyGenerated.setAlpha(alpha);
encryptedMessages.setAlpha(alpha);
}
private void setupToolbar() {
toolbar.setNavigationOnClickListener(v -> dismiss());
}
private void setupRecycler() {
adapter = new InsightsInsecureRecipientsAdapter(this::handleInviteRecipient);
insecureRecipients.setAdapter(adapter);
}
private void initializeViewModel() {
final InsightsDashboardViewModel.Repository repository = new InsightsRepository(requireContext());
final InsightsDashboardViewModel.Factory factory = new InsightsDashboardViewModel.Factory(repository);
viewModel = new ViewModelProvider(this, factory).get(InsightsDashboardViewModel.class);
viewModel.getState().observe(getViewLifecycleOwner(), state -> {
updateInsecurePercent(state.getData());
updateInsecureRecipients(state.getInsecureRecipients());
updateUserAvatar(state.getUserAvatar());
});
}
private void updateInsecurePercent(@Nullable InsightsData insightsData) {
if (insightsData == null) return;
if (insightsData.hasEnoughData()) {
setTitleAndDescriptionText(insightsData.getPercentInsecure());
animateProgress(insightsData.getPercentInsecure());
} else {
setNotEnoughDataText();
animateNotEnoughData();
}
}
private void animateProgress(int insecurePercent) {
startAConversation.setVisibility(View.GONE);
if (animatorSet == null) {
animatorSet = InsightsAnimatorSetFactory.create(insecurePercent,
this::setProgressPercentage,
this::setDashboardDetailsAlpha,
this::setPercentSecureScale,
insecurePercent == 0 ? this::setLottieProgress : null);
if (insecurePercent == 0) {
animatorSet.addListener(new ToolbarBackgroundColorAnimationListener());
}
animatorSet.start();
}
}
private void setProgressPercentage(float percent) {
securePercentage.setText(String.valueOf(Math.round(percent * 100)));
progress.setProgress(percent);
}
private void setPercentSecureScale(float scale) {
progressContainer.setScaleX(scale);
progressContainer.setScaleY(scale);
}
private void setLottieProgress(float progress) {
lottieAnimationView.setProgress(progress);
}
private void setTitleAndDescriptionText(int insecurePercent) {
startAConversation.setVisibility(View.GONE);
progressContainer.setVisibility(View.VISIBLE);
insecureRecipients.setVisibility(View.VISIBLE);
encryptedMessages.setText(R.string.InsightsDashboardFragment__encrypted_messages);
tagline.setText(getString(R.string.InsightsDashboardFragment__signal_protocol_automatically_protected, 100 - insecurePercent, InsightsConstants.PERIOD_IN_DAYS));
if (insecurePercent == 0) {
lottieAnimationView.setVisibility(View.VISIBLE);
title.setVisibility(View.GONE);
description.setVisibility(View.GONE);
} else {
lottieAnimationView.setVisibility(View.GONE);
title.setText(R.string.InsightsDashboardFragment__spread_the_word);
description.setText(R.string.InsightsDashboardFragment__invite_your_contacts);
title.setVisibility(View.VISIBLE);
description.setVisibility(View.VISIBLE);
}
}
private void setNotEnoughDataText() {
startAConversation.setVisibility(View.VISIBLE);
progressContainer.setVisibility(View.INVISIBLE);
insecureRecipients.setVisibility(View.GONE);
encryptedMessages.setText(R.string.InsightsDashboardFragment__not_enough_data);
tagline.setText(getString(R.string.InsightsDashboardFragment__your_insights_percentage_is_calculated_based_on, InsightsConstants.PERIOD_IN_DAYS));
}
private void animateNotEnoughData() {
if (animatorSet == null) {
animatorSet = InsightsAnimatorSetFactory.create(0, null, this::setNotEnoughDataAlpha, null, null);
animatorSet.start();
}
}
private void setNotEnoughDataAlpha(float alpha) {
encryptedMessages.setAlpha(alpha);
tagline.setAlpha(alpha);
startAConversation.setAlpha(alpha);
}
private void updateInsecureRecipients(@NonNull List<Recipient> recipients) {
adapter.updateData(recipients);
}
private void updateUserAvatar(@Nullable InsightsUserAvatar userAvatar) {
if (userAvatar == null) avatarImageView.setImageDrawable(null);
else userAvatar.load(avatarImageView);
}
private void handleInviteRecipient(final @NonNull Recipient recipient) {
new AlertDialog.Builder(requireContext())
.setTitle(getResources().getQuantityString(R.plurals.InviteActivity_send_sms_invites, 1, 1))
.setMessage(getString(R.string.InviteActivity_lets_switch_to_signal, getString(R.string.install_url)))
.setPositiveButton(R.string.InsightsDashboardFragment__send, (dialog, which) -> viewModel.sendSmsInvite(recipient))
.setNegativeButton(R.string.InsightsDashboardFragment__cancel, (dialog, which) -> dialog.dismiss())
.show();
}
@Override
public void onDestroyView() {
if (animatorSet != null) {
animatorSet.cancel();
animatorSet = null;
}
super.onDestroyView();
}
private final class ToolbarBackgroundColorAnimationListener implements Animator.AnimatorListener {
@Override
public void onAnimationStart(Animator animation) {
toolbar.setBackgroundResource(R.color.transparent);
}
@Override
public void onAnimationEnd(Animator animation) {
toolbar.setBackgroundColor(ThemeUtil.getThemedColor(requireContext(), android.R.attr.windowBackground));
}
@Override
public void onAnimationCancel(Animator animation) {
toolbar.setBackgroundColor(ThemeUtil.getThemedColor(requireContext(), android.R.attr.windowBackground));
}
@Override
public void onAnimationRepeat(Animator animation) {
}
}
}