From addf8d89962bf3de6d70330f9264d0e4d866613e Mon Sep 17 00:00:00 2001 From: cyberta Date: Sat, 29 Jul 2023 17:15:05 +0200 Subject: update design and UX for provider setup --- .../fragments/ConfigureProviderFragment.java | 163 +++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java (limited to 'app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java new file mode 100644 index 00000000..ceed2c3c --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java @@ -0,0 +1,163 @@ +package se.leap.bitmaskclient.providersetup.fragments; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; +import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; +import static se.leap.bitmaskclient.base.utils.ViewHelper.animateContainerVisibility; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER; +import static se.leap.bitmaskclient.tor.TorStatusObservable.getBootstrapProgress; +import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastLogs; +import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastSnowflakeLog; +import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastTorLog; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.viewpager2.widget.ViewPager2; + +import java.util.List; +import java.util.Observable; +import java.util.Observer; + +import se.leap.bitmaskclient.base.utils.PreferenceHelper; +import se.leap.bitmaskclient.databinding.FConfigureProviderBinding; +import se.leap.bitmaskclient.providersetup.ProviderAPICommand; +import se.leap.bitmaskclient.providersetup.TorLogAdapter; +import se.leap.bitmaskclient.providersetup.activities.SetupInterface; +import se.leap.bitmaskclient.tor.TorStatusObservable; + +public class ConfigureProviderFragment extends Fragment implements Observer { + + public static ConfigureProviderFragment newInstance(int position) { + return new ConfigureProviderFragment(position); + } + + FConfigureProviderBinding binding; + private SetupInterface setupInterface; + private boolean isExpanded = false; + private final int position; + private ViewPager2.OnPageChangeCallback viewPagerCallback; + private TorLogAdapter torLogAdapter; + + + public ConfigureProviderFragment(int position) { + this.position = position; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + binding = FConfigureProviderBinding.inflate(inflater, container, false); + binding.detailContainer.setVisibility(PreferenceHelper.getUseSnowflake(getContext()) ? VISIBLE : GONE); + binding.detailHeaderContainer.setOnClickListener(v -> { + binding.ivExpand.animate().setDuration(250).rotation(isExpanded ? 0 : 270); + showConnectionDetails(); + animateContainerVisibility(binding.expandableDetailContainer, isExpanded); + isExpanded = !isExpanded; + }); + + binding.ivExpand.animate().setDuration(0).rotation(270); + return binding.getRoot(); + } + + + + @Override + public void onDestroyView() { + super.onDestroyView(); + binding = null; + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + setupInterface = (SetupInterface) getActivity(); + viewPagerCallback = new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageSelected(int position) { + super.onPageSelected(position); + if (position == ConfigureProviderFragment.this.position) { + binding.detailContainer.setVisibility(PreferenceHelper.getUseSnowflake(getContext()) ? VISIBLE : GONE); + setupInterface.setNavigationButtonHidden(true); + ProviderAPICommand.execute(context, SET_UP_PROVIDER, setupInterface.getSelectedProvider()); + } + } + }; + setupInterface.registerOnPageChangeCallback(viewPagerCallback); + TorStatusObservable.getInstance().addObserver(this); + } + + @Override + public void onDetach() { + super.onDetach(); + TorStatusObservable.getInstance().deleteObserver(this); + setupInterface.removeOnPageChangeCallback(viewPagerCallback); + setupInterface = null; + } + + protected void showConnectionDetails() { + LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext()); + binding.connectionDetailLogs.setLayoutManager(layoutManager); + torLogAdapter = new TorLogAdapter(getLastLogs()); + binding.connectionDetailLogs.setAdapter(torLogAdapter); + + binding.connectionDetailLogs.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState != SCROLL_STATE_IDLE) { + torLogAdapter.postponeUpdate = true; + } else if (newState == SCROLL_STATE_IDLE && getFirstVisibleItemPosion() == 0) { + torLogAdapter.postponeUpdate = false; + } + } + }); + + binding.snowflakeState.setText(getLastSnowflakeLog()); + binding.torState.setText(getLastTorLog()); + } + + private int getFirstVisibleItemPosion() { + return ((LinearLayoutManager) binding.connectionDetailLogs.getLayoutManager()).findFirstVisibleItemPosition(); + } + + @Override + public void update(Observable o, Object arg) { + if (o instanceof TorStatusObservable) { + Activity activity = getActivity(); + if (activity == null) { + return; + } + activity.runOnUiThread(() -> { + if (TorStatusObservable.getStatus() != TorStatusObservable.TorStatus.OFF) { + if (binding.connectionDetailContainer.getVisibility() == GONE) { + showConnectionDetails(); + } else { + setLogs(getLastTorLog(), getLastSnowflakeLog(), getLastLogs()); + } + } + binding.progressSpinner.update(getBootstrapProgress()); + }); + } + } + + protected void setLogs(String torLog, String snowflakeLog, List lastLogs) { + torLogAdapter.updateData(lastLogs); + binding.torState.setText(torLog); + binding.snowflakeState.setText(snowflakeLog); + } +} \ No newline at end of file -- cgit v1.2.3