kopia lustrzana https://github.com/ryukoposting/Signal-Android
Maintain app bar layout when switching tabs.
rodzic
ffad2c7386
commit
f798866619
|
@ -10,7 +10,6 @@ import android.view.View;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.lifecycle.Transformations;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController;
|
||||
|
@ -19,7 +18,6 @@ import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceTransferLock
|
|||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.stories.Stories;
|
||||
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabRepository;
|
||||
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsState;
|
||||
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel;
|
||||
import org.thoughtcrime.securesms.util.AppStartup;
|
||||
import org.thoughtcrime.securesms.util.CachedInflater;
|
||||
|
@ -60,8 +58,6 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
|||
ConversationListTabRepository repository = new ConversationListTabRepository();
|
||||
ConversationListTabsViewModel.Factory factory = new ConversationListTabsViewModel.Factory(repository);
|
||||
|
||||
navigator.onCreate(savedInstanceState);
|
||||
|
||||
handleGroupLinkInIntent(getIntent());
|
||||
handleProxyInIntent(getIntent());
|
||||
handleSignalMeIntent(getIntent());
|
||||
|
@ -69,18 +65,6 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
|||
CachedInflater.from(this).clear();
|
||||
|
||||
conversationListTabsViewModel = new ViewModelProvider(this, factory).get(ConversationListTabsViewModel.class);
|
||||
Transformations.distinctUntilChanged(Transformations.map(conversationListTabsViewModel.getState(), ConversationListTabsState::getTab))
|
||||
.observe(this, tab -> {
|
||||
switch (tab) {
|
||||
case CHATS:
|
||||
getSupportFragmentManager().popBackStack();
|
||||
break;
|
||||
case STORIES:
|
||||
navigator.goToStories();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
updateTabVisibility();
|
||||
}
|
||||
|
||||
|
@ -138,7 +122,7 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
|||
} else {
|
||||
findViewById(R.id.conversation_list_tabs).setVisibility(View.GONE);
|
||||
WindowUtil.setNavigationBarColor(getWindow(), ContextCompat.getColor(this, R.color.signal_background_primary));
|
||||
navigator.goToChats();
|
||||
conversationListTabsViewModel.onChatsSelected();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,26 +2,19 @@ package org.thoughtcrime.securesms;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents;
|
||||
import org.thoughtcrime.securesms.conversationlist.ConversationListArchiveFragment;
|
||||
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
|
||||
import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity;
|
||||
import org.thoughtcrime.securesms.insights.InsightsLauncher;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.stories.landing.StoriesLandingFragment;
|
||||
|
||||
public class MainNavigator {
|
||||
|
||||
public static final String STORIES_TAG = "STORIES";
|
||||
|
||||
public static final int REQUEST_CONFIG_CHANGES = 901;
|
||||
|
||||
private final MainActivity activity;
|
||||
|
@ -38,16 +31,6 @@ public class MainNavigator {
|
|||
return ((MainActivity) activity).getNavigator();
|
||||
}
|
||||
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
if (savedInstanceState != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
getFragmentManager().beginTransaction()
|
||||
.add(R.id.fragment_container, ConversationListFragment.newInstance())
|
||||
.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the back pressed was handled in our own custom way, false if it should be given
|
||||
* to the system to do the default behavior.
|
||||
|
@ -76,29 +59,6 @@ public class MainNavigator {
|
|||
activity.startActivityForResult(AppSettingsActivity.home(activity), REQUEST_CONFIG_CHANGES);
|
||||
}
|
||||
|
||||
public void goToArchiveList() {
|
||||
getFragmentManager().beginTransaction()
|
||||
.setCustomAnimations(R.anim.slide_from_end, R.anim.slide_to_start, R.anim.slide_from_start, R.anim.slide_to_end)
|
||||
.replace(R.id.fragment_container, ConversationListArchiveFragment.newInstance())
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public void goToStories() {
|
||||
if (getFragmentManager().findFragmentByTag(STORIES_TAG) == null) {
|
||||
getFragmentManager().beginTransaction()
|
||||
.replace(R.id.fragment_container, new StoriesLandingFragment(), STORIES_TAG)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
public void goToChats() {
|
||||
if (getFragmentManager().findFragmentByTag(STORIES_TAG) != null) {
|
||||
getFragmentManager().popBackStack();
|
||||
}
|
||||
}
|
||||
|
||||
public void goToGroupCreation() {
|
||||
activity.startActivity(CreateGroupActivity.newIntent(activity));
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ import androidx.annotation.WorkerThread;
|
|||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavHostController;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
@ -62,7 +65,7 @@ public class ConversationListArchiveFragment extends ConversationListFragment im
|
|||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
toolbar = new Stub<>(view.findViewById(R.id.toolbar_basic));
|
||||
toolbar = requireCallback().getBasicToolbar();
|
||||
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
|
@ -71,8 +74,7 @@ public class ConversationListArchiveFragment extends ConversationListFragment im
|
|||
cameraFab = view.findViewById(R.id.camera_fab);
|
||||
emptyState = new Stub<>(view.findViewById(R.id.empty_state));
|
||||
|
||||
((AppCompatActivity) requireActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
toolbar.get().setNavigationOnClickListener(v -> requireActivity().onBackPressed());
|
||||
toolbar.get().setNavigationOnClickListener(v -> NavHostFragment.findNavController(this).popBackStack());
|
||||
toolbar.get().setTitle(R.string.AndroidManifest_archived_conversations);
|
||||
|
||||
fab.hide();
|
||||
|
|
|
@ -44,6 +44,7 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.IdRes;
|
||||
|
@ -63,6 +64,8 @@ import androidx.core.view.ViewCompat;
|
|||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavHostController;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -187,7 +190,6 @@ import static org.thoughtcrime.securesms.components.TooltipPopup.POSITION_BELOW;
|
|||
public class ConversationListFragment extends MainFragment implements ActionMode.Callback,
|
||||
ConversationListAdapter.OnConversationClickListener,
|
||||
ConversationListSearchAdapter.EventListener,
|
||||
MainNavigator.BackHandler,
|
||||
MegaphoneActionController
|
||||
{
|
||||
public static final short MESSAGE_REQUESTS_REQUEST_CODE_CREATE_NAME = 32562;
|
||||
|
@ -206,12 +208,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
private TextView searchEmptyState;
|
||||
private PulsingFloatingActionButton fab;
|
||||
private PulsingFloatingActionButton cameraFab;
|
||||
private Stub<SearchToolbar> searchToolbar;
|
||||
private ImageView notificationProfileStatus;
|
||||
private ImageView proxyStatus;
|
||||
private ImageView searchAction;
|
||||
private View toolbarShadow;
|
||||
private View unreadPaymentsDot;
|
||||
private ConversationListViewModel viewModel;
|
||||
private RecyclerView.Adapter activeAdapter;
|
||||
private ConversationListAdapter defaultAdapter;
|
||||
|
@ -225,7 +222,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
private Stub<FrameLayout> voiceNotePlayerViewStub;
|
||||
private VoiceNotePlayerView voiceNotePlayerView;
|
||||
private SignalBottomActionBar bottomActionBar;
|
||||
private TopToastPopup previousTopToastPopup;
|
||||
|
||||
protected ConversationListArchiveItemDecoration archiveDecoration;
|
||||
protected ConversationListItemAnimator itemAnimator;
|
||||
|
@ -265,25 +261,16 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
fab = view.findViewById(R.id.fab);
|
||||
cameraFab = view.findViewById(R.id.camera_fab);
|
||||
searchEmptyState = view.findViewById(R.id.search_no_results);
|
||||
searchAction = view.findViewById(R.id.search_action);
|
||||
toolbarShadow = view.findViewById(R.id.conversation_list_toolbar_shadow);
|
||||
notificationProfileStatus = view.findViewById(R.id.conversation_list_notification_profile_status);
|
||||
proxyStatus = view.findViewById(R.id.conversation_list_proxy_status);
|
||||
unreadPaymentsDot = view.findViewById(R.id.unread_payments_indicator);
|
||||
bottomActionBar = view.findViewById(R.id.conversation_list_bottom_action_bar);
|
||||
reminderView = new Stub<>(view.findViewById(R.id.reminder));
|
||||
emptyState = new Stub<>(view.findViewById(R.id.empty_state));
|
||||
searchToolbar = new Stub<>(view.findViewById(R.id.search_toolbar));
|
||||
megaphoneContainer = new Stub<>(view.findViewById(R.id.megaphone_container));
|
||||
paymentNotificationView = new Stub<>(view.findViewById(R.id.payments_notification));
|
||||
voiceNotePlayerViewStub = new Stub<>(view.findViewById(R.id.voice_note_player));
|
||||
|
||||
Toolbar toolbar = getToolbar(view);
|
||||
toolbar.setVisibility(View.VISIBLE);
|
||||
((AppCompatActivity) requireActivity()).setSupportActionBar(toolbar);
|
||||
|
||||
notificationProfileStatus.setOnClickListener(v -> handleNotificationProfile());
|
||||
proxyStatus.setOnClickListener(v -> onProxyStatusClicked());
|
||||
|
||||
fab.show();
|
||||
cameraFab.show();
|
||||
|
@ -321,13 +308,18 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
|
||||
RatingManager.showRatingDialogIfNecessary(requireContext());
|
||||
|
||||
TooltipCompat.setTooltipText(searchAction, getText(R.string.SearchToolbar_search_for_conversations_contacts_and_messages));
|
||||
}
|
||||
TooltipCompat.setTooltipText(requireCallback().getSearchAction(), getText(R.string.SearchToolbar_search_for_conversations_contacts_and_messages));
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
previousTopToastPopup = null;
|
||||
super.onDestroyView();
|
||||
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
if (!closeSearchIfOpen()) {
|
||||
if (!NavHostFragment.findNavController(ConversationListFragment.this).popBackStack()) {
|
||||
requireActivity().finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -342,11 +334,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
InsightsLauncher.showInsightsModal(requireContext(), requireFragmentManager());
|
||||
}
|
||||
|
||||
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), Recipient::self, this::initializeProfileIcon);
|
||||
|
||||
initializeSettingsTouchTarget();
|
||||
|
||||
if ((!searchToolbar.resolved() || !searchToolbar.get().isVisible()) && list.getAdapter() != defaultAdapter) {
|
||||
if ((!requireCallback().getSearchToolbar().resolved() || !requireCallback().getSearchToolbar().get().isVisible()) && list.getAdapter() != defaultAdapter) {
|
||||
list.removeItemDecoration(searchAdapterDecoration);
|
||||
setAdapter(defaultAdapter);
|
||||
}
|
||||
|
@ -431,16 +419,12 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
return closeSearchIfOpen();
|
||||
}
|
||||
|
||||
private boolean closeSearchIfOpen() {
|
||||
if ((searchToolbar.resolved() && searchToolbar.get().isVisible()) || activeAdapter == searchAdapter) {
|
||||
if ((requireCallback().getSearchToolbar().resolved() && requireCallback().getSearchToolbar().get().isVisible()) || activeAdapter == searchAdapter) {
|
||||
list.removeItemDecoration(searchAdapterDecoration);
|
||||
setAdapter(defaultAdapter);
|
||||
searchToolbar.get().collapse();
|
||||
requireCallback().getSearchToolbar().get().collapse();
|
||||
requireCallback().onSearchClosed();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -475,7 +459,8 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
|
||||
@Override
|
||||
public void onShowArchiveClick() {
|
||||
getNavigator().goToArchiveList();
|
||||
NavHostFragment.findNavController(this)
|
||||
.navigate(ConversationListFragmentDirections.actionConversationListFragmentToConversationListArchiveFragment());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -558,26 +543,13 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
imm.hideSoftInputFromWindow(requireView().getWindowToken(), 0);
|
||||
}
|
||||
|
||||
private void initializeProfileIcon(@NonNull Recipient recipient) {
|
||||
ImageView icon = requireView().findViewById(R.id.toolbar_icon);
|
||||
|
||||
BadgeImageView imageView = requireView().findViewById(R.id.toolbar_badge);
|
||||
imageView.setBadgeFromRecipient(recipient);
|
||||
|
||||
AvatarUtil.loadIconIntoImageView(recipient, icon, getResources().getDimensionPixelSize(R.dimen.toolbar_avatar_size));
|
||||
}
|
||||
|
||||
private void initializeSettingsTouchTarget() {
|
||||
View touchArea = requireView().findViewById(R.id.toolbar_settings_touch_area);
|
||||
touchArea.setOnClickListener(v -> getNavigator().goToAppSettings());
|
||||
}
|
||||
|
||||
private void initializeSearchListener() {
|
||||
searchAction.setOnClickListener(v -> {
|
||||
searchToolbar.get().display(searchAction.getX() + (searchAction.getWidth() / 2.0f),
|
||||
searchAction.getY() + (searchAction.getHeight() / 2.0f));
|
||||
requireCallback().getSearchAction().setOnClickListener(v -> {
|
||||
requireCallback().onSearchOpened();
|
||||
requireCallback().getSearchToolbar().get().display(requireCallback().getSearchAction().getX() + (requireCallback().getSearchAction().getWidth() / 2.0f),
|
||||
requireCallback().getSearchAction().getY() + (requireCallback().getSearchAction().getHeight() / 2.0f));
|
||||
|
||||
searchToolbar.get().setListener(new SearchToolbar.SearchListener() {
|
||||
requireCallback().getSearchToolbar().get().setListener(new SearchToolbar.SearchListener() {
|
||||
@Override
|
||||
public void onSearchTextChange(String text) {
|
||||
String trimmed = text.trim();
|
||||
|
@ -602,6 +574,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
public void onSearchClosed() {
|
||||
list.removeItemDecoration(searchAdapterDecoration);
|
||||
setAdapter(defaultAdapter);
|
||||
requireCallback().onSearchClosed();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -697,8 +670,8 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
viewModel.getMegaphone().observe(getViewLifecycleOwner(), this::onMegaphoneChanged);
|
||||
viewModel.getConversationList().observe(getViewLifecycleOwner(), this::onConversationListChanged);
|
||||
viewModel.hasNoConversations().observe(getViewLifecycleOwner(), this::updateEmptyState);
|
||||
viewModel.getNotificationProfiles().observe(getViewLifecycleOwner(), this::updateNotificationProfileStatus);
|
||||
viewModel.getPipeState().observe(getViewLifecycleOwner(), this::updateProxyStatus);
|
||||
viewModel.getNotificationProfiles().observe(getViewLifecycleOwner(), profiles -> requireCallback().updateNotificationProfileStatus(profiles));
|
||||
viewModel.getPipeState().observe(getViewLifecycleOwner(), pipeState -> requireCallback().updateProxyStatus(pipeState));
|
||||
|
||||
appForegroundObserver = new AppForegroundObserver.Listener() {
|
||||
@Override
|
||||
|
@ -742,7 +715,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
|
||||
private void animatePaymentUnreadStatusIn() {
|
||||
paymentNotificationView.get().setVisibility(View.VISIBLE);
|
||||
unreadPaymentsDot.animate().alpha(1);
|
||||
requireCallback().getUnreadPaymentsDot().animate().alpha(1);
|
||||
}
|
||||
|
||||
private void animatePaymentUnreadStatusOut() {
|
||||
|
@ -750,7 +723,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
paymentNotificationView.get().setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
unreadPaymentsDot.animate().alpha(0);
|
||||
requireCallback().getUnreadPaymentsDot().animate().alpha(0);
|
||||
}
|
||||
|
||||
private void onSearchResultChanged(@Nullable SearchResult result) {
|
||||
|
@ -1094,90 +1067,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
}
|
||||
}
|
||||
|
||||
private void updateNotificationProfileStatus(@NonNull List<NotificationProfile> notificationProfiles) {
|
||||
NotificationProfile activeProfile = NotificationProfiles.getActiveProfile(notificationProfiles);
|
||||
|
||||
if (activeProfile != null) {
|
||||
if (activeProfile.getId() != SignalStore.notificationProfileValues().getLastProfilePopup()) {
|
||||
requireView().postDelayed(() -> {
|
||||
SignalStore.notificationProfileValues().setLastProfilePopup(activeProfile.getId());
|
||||
SignalStore.notificationProfileValues().setLastProfilePopupTime(System.currentTimeMillis());
|
||||
|
||||
if (previousTopToastPopup != null && previousTopToastPopup.isShowing()) {
|
||||
previousTopToastPopup.dismiss();
|
||||
}
|
||||
|
||||
ViewGroup view = ((ViewGroup) requireView());
|
||||
Fragment fragment = getParentFragmentManager().findFragmentByTag(BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
|
||||
if (fragment != null && fragment.isAdded() && fragment.getView() != null) {
|
||||
view = ((ViewGroup) fragment.requireView());
|
||||
}
|
||||
|
||||
try {
|
||||
previousTopToastPopup = TopToastPopup.show(view, R.drawable.ic_moon_16, getString(R.string.ConversationListFragment__s_on, activeProfile.getName()));
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Unable to show toast popup", e);
|
||||
}
|
||||
}, 500L);
|
||||
}
|
||||
|
||||
notificationProfileStatus.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
notificationProfileStatus.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (!SignalStore.notificationProfileValues().getHasSeenTooltip() && Util.hasItems(notificationProfiles)) {
|
||||
View target = findOverflowMenuButton(getToolbar(requireView()));
|
||||
if (target != null) {
|
||||
TooltipPopup.forTarget(target)
|
||||
.setText(R.string.ConversationListFragment__turn_your_notification_profile_on_or_off_here)
|
||||
.setBackgroundTint(ContextCompat.getColor(requireContext(), R.color.signal_button_primary))
|
||||
.setTextColor(ContextCompat.getColor(requireContext(), R.color.signal_button_primary_text))
|
||||
.setOnDismissListener(() -> SignalStore.notificationProfileValues().setHasSeenTooltip(true))
|
||||
.show(POSITION_BELOW);
|
||||
} else {
|
||||
Log.w(TAG, "Unable to find overflow menu to show Notification Profile tooltip");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable View findOverflowMenuButton(@NonNull Toolbar viewGroup) {
|
||||
for (int i = 0, count = viewGroup.getChildCount(); i < count; i++) {
|
||||
View v = viewGroup.getChildAt(i);
|
||||
if (v instanceof ActionMenuView) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void updateProxyStatus(@NonNull WebSocketConnectionState state) {
|
||||
if (SignalStore.proxy().isProxyEnabled()) {
|
||||
proxyStatus.setVisibility(View.VISIBLE);
|
||||
|
||||
switch (state) {
|
||||
case CONNECTING:
|
||||
case DISCONNECTING:
|
||||
case DISCONNECTED:
|
||||
proxyStatus.setImageResource(R.drawable.ic_proxy_connecting_24);
|
||||
break;
|
||||
case CONNECTED:
|
||||
proxyStatus.setImageResource(R.drawable.ic_proxy_connected_24);
|
||||
break;
|
||||
case AUTHENTICATION_FAILED:
|
||||
case FAILED:
|
||||
proxyStatus.setImageResource(R.drawable.ic_proxy_failed_24);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
proxyStatus.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void onProxyStatusClicked() {
|
||||
startActivity(AppSettingsActivity.proxy(requireContext()));
|
||||
}
|
||||
|
||||
protected void onPostSubmitList(int conversationCount) {
|
||||
if (conversationCount >= 6 && (SignalStore.onboarding().shouldShowInviteFriends() || SignalStore.onboarding().shouldShowNewGroup())) {
|
||||
SignalStore.onboarding().clearAll();
|
||||
|
@ -1361,8 +1250,12 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
bottomActionBar.setItems(items);
|
||||
}
|
||||
|
||||
protected Callback requireCallback() {
|
||||
return ((Callback) getParentFragment().getParentFragment());
|
||||
}
|
||||
|
||||
protected Toolbar getToolbar(@NonNull View rootView) {
|
||||
return rootView.findViewById(R.id.toolbar);
|
||||
return requireCallback().getToolbar();
|
||||
}
|
||||
|
||||
protected @PluralsRes int getArchivedSnackbarTitleRes() {
|
||||
|
@ -1668,6 +1561,19 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
MainNavigator.get(requireActivity()).goToConversation(threadRecipientId, threadId, ThreadDatabase.DistributionTypes.DEFAULT, (int) messagePositionInThread);
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
@NonNull Toolbar getToolbar();
|
||||
@NonNull ImageView getSearchAction();
|
||||
@NonNull Stub<SearchToolbar> getSearchToolbar();
|
||||
@NonNull View getUnreadPaymentsDot();
|
||||
@NonNull Stub<Toolbar> getBasicToolbar();
|
||||
|
||||
void updateNotificationProfileStatus(@NonNull List<NotificationProfile> notificationProfiles);
|
||||
void updateProxyStatus(@NonNull WebSocketConnectionState state);
|
||||
void onSearchOpened();
|
||||
void onSearchClosed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,280 @@
|
|||
package org.thoughtcrime.securesms.main
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.ActionMenuView
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
import org.thoughtcrime.securesms.components.SearchToolbar
|
||||
import org.thoughtcrime.securesms.components.TooltipPopup
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
|
||||
import org.thoughtcrime.securesms.components.settings.app.notifications.manual.NotificationProfileSelectionFragment
|
||||
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfiles
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.stories.tabs.ConversationListTab
|
||||
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsState
|
||||
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel
|
||||
import org.thoughtcrime.securesms.util.AvatarUtil
|
||||
import org.thoughtcrime.securesms.util.BottomSheetUtil
|
||||
import org.thoughtcrime.securesms.util.TopToastPopup
|
||||
import org.thoughtcrime.securesms.util.TopToastPopup.Companion.show
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask
|
||||
import org.thoughtcrime.securesms.util.views.Stub
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
|
||||
|
||||
class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_fragment), ConversationListFragment.Callback {
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(MainActivityListHostFragment::class.java)
|
||||
}
|
||||
|
||||
private val conversationListTabsViewModel: ConversationListTabsViewModel by viewModels(ownerProducer = { requireActivity() })
|
||||
|
||||
private lateinit var _toolbar: Toolbar
|
||||
private lateinit var _basicToolbar: Stub<Toolbar>
|
||||
private lateinit var notificationProfileStatus: ImageView
|
||||
private lateinit var proxyStatus: ImageView
|
||||
private lateinit var _searchToolbar: Stub<SearchToolbar>
|
||||
private lateinit var _searchAction: ImageView
|
||||
private lateinit var _unreadPaymentsDot: View
|
||||
|
||||
private var previousTopToastPopup: TopToastPopup? = null
|
||||
|
||||
private val destinationChangedListener = DestinationChangedListener()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
_toolbar = view.findViewById(R.id.toolbar)
|
||||
_basicToolbar = Stub(view.findViewById(R.id.toolbar_basic))
|
||||
notificationProfileStatus = view.findViewById(R.id.conversation_list_notification_profile_status)
|
||||
proxyStatus = view.findViewById(R.id.conversation_list_proxy_status)
|
||||
_searchAction = view.findViewById(R.id.search_action)
|
||||
_searchToolbar = Stub(view.findViewById(R.id.search_toolbar))
|
||||
_unreadPaymentsDot = view.findViewById(R.id.unread_payments_indicator)
|
||||
|
||||
notificationProfileStatus.setOnClickListener { handleNotificationProfile() }
|
||||
proxyStatus.setOnClickListener { onProxyStatusClicked() }
|
||||
|
||||
initializeSettingsTouchTarget()
|
||||
|
||||
(requireActivity() as AppCompatActivity).setSupportActionBar(_toolbar)
|
||||
|
||||
conversationListTabsViewModel.state.observe(viewLifecycleOwner) { state ->
|
||||
val controller: NavController = requireView().findViewById<View>(R.id.fragment_container).findNavController()
|
||||
when (controller.currentDestination?.id) {
|
||||
R.id.conversationListFragment -> goToStateFromConversationList(state, controller)
|
||||
R.id.conversationListArchiveFragment -> goToStateFromConversationArchiveList(state, controller)
|
||||
R.id.storiesLandingFragment -> goToStateFromStories(state, controller)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun goToStateFromConversationArchiveList(state: ConversationListTabsState, navController: NavController) {
|
||||
if (state.tab == ConversationListTab.CHATS) {
|
||||
return
|
||||
} else {
|
||||
navController.navigate(R.id.action_conversationListArchiveFragment_to_storiesLandingFragment)
|
||||
}
|
||||
}
|
||||
|
||||
private fun goToStateFromConversationList(state: ConversationListTabsState, navController: NavController) {
|
||||
if (state.tab == ConversationListTab.CHATS) {
|
||||
return
|
||||
} else {
|
||||
navController.navigate(R.id.action_conversationListFragment_to_storiesLandingFragment)
|
||||
}
|
||||
}
|
||||
|
||||
private fun goToStateFromStories(state: ConversationListTabsState, navController: NavController) {
|
||||
if (state.tab == ConversationListTab.STORIES) {
|
||||
return
|
||||
} else {
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
SimpleTask.run(viewLifecycleOwner.lifecycle, { Recipient.self() }, ::initializeProfileIcon)
|
||||
|
||||
requireView()
|
||||
.findViewById<View>(R.id.fragment_container)
|
||||
.findNavController()
|
||||
.addOnDestinationChangedListener(destinationChangedListener)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
requireView()
|
||||
.findViewById<View>(R.id.fragment_container)
|
||||
.findNavController()
|
||||
.removeOnDestinationChangedListener(destinationChangedListener)
|
||||
}
|
||||
|
||||
private fun presentToolbarForConversationListFragment() {
|
||||
_toolbar.visible = true
|
||||
_searchAction.visible = true
|
||||
if (_basicToolbar.resolved()) {
|
||||
_basicToolbar.get().visible = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentToolbarForConversationListArchiveFragment() {
|
||||
_toolbar.visible = false
|
||||
_basicToolbar.get().visible = true
|
||||
}
|
||||
|
||||
private fun presentToolbarForStoriesLandingFragment() {
|
||||
_toolbar.visible = true
|
||||
_searchAction.visible = false
|
||||
if (_basicToolbar.resolved()) {
|
||||
_basicToolbar.get().visible = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
previousTopToastPopup = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun getToolbar(): Toolbar {
|
||||
return _toolbar
|
||||
}
|
||||
|
||||
override fun getSearchAction(): ImageView {
|
||||
return _searchAction
|
||||
}
|
||||
|
||||
override fun getSearchToolbar(): Stub<SearchToolbar> {
|
||||
return _searchToolbar
|
||||
}
|
||||
|
||||
override fun getUnreadPaymentsDot(): View {
|
||||
return _unreadPaymentsDot
|
||||
}
|
||||
|
||||
override fun getBasicToolbar(): Stub<Toolbar> {
|
||||
return _basicToolbar
|
||||
}
|
||||
|
||||
override fun onSearchOpened() {
|
||||
conversationListTabsViewModel.onSearchOpened()
|
||||
}
|
||||
|
||||
override fun onSearchClosed() {
|
||||
conversationListTabsViewModel.onSearchClosed()
|
||||
}
|
||||
|
||||
private fun initializeProfileIcon(recipient: Recipient) {
|
||||
Log.d(TAG, "Initializing profile icon")
|
||||
val icon = requireView().findViewById<ImageView>(R.id.toolbar_icon)
|
||||
val imageView: BadgeImageView = requireView().findViewById(R.id.toolbar_badge)
|
||||
imageView.setBadgeFromRecipient(recipient)
|
||||
AvatarUtil.loadIconIntoImageView(recipient, icon, resources.getDimensionPixelSize(R.dimen.toolbar_avatar_size))
|
||||
}
|
||||
|
||||
private fun initializeSettingsTouchTarget() {
|
||||
val touchArea = requireView().findViewById<View>(R.id.toolbar_settings_touch_area)
|
||||
touchArea.setOnClickListener { startActivity(AppSettingsActivity.home(requireContext())) }
|
||||
}
|
||||
|
||||
private fun handleNotificationProfile() {
|
||||
NotificationProfileSelectionFragment.show(parentFragmentManager)
|
||||
}
|
||||
|
||||
private fun onProxyStatusClicked() {
|
||||
startActivity(AppSettingsActivity.proxy(requireContext()))
|
||||
}
|
||||
|
||||
override fun updateProxyStatus(state: WebSocketConnectionState) {
|
||||
if (SignalStore.proxy().isProxyEnabled) {
|
||||
proxyStatus.visibility = View.VISIBLE
|
||||
when (state) {
|
||||
WebSocketConnectionState.CONNECTING, WebSocketConnectionState.DISCONNECTING, WebSocketConnectionState.DISCONNECTED -> proxyStatus.setImageResource(R.drawable.ic_proxy_connecting_24)
|
||||
WebSocketConnectionState.CONNECTED -> proxyStatus.setImageResource(R.drawable.ic_proxy_connected_24)
|
||||
WebSocketConnectionState.AUTHENTICATION_FAILED, WebSocketConnectionState.FAILED -> proxyStatus.setImageResource(R.drawable.ic_proxy_failed_24)
|
||||
else -> proxyStatus.visibility = View.GONE
|
||||
}
|
||||
} else {
|
||||
proxyStatus.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateNotificationProfileStatus(notificationProfiles: List<NotificationProfile>) {
|
||||
val activeProfile = NotificationProfiles.getActiveProfile(notificationProfiles)
|
||||
if (activeProfile != null) {
|
||||
if (activeProfile.id != SignalStore.notificationProfileValues().lastProfilePopup) {
|
||||
requireView().postDelayed({
|
||||
SignalStore.notificationProfileValues().lastProfilePopup = activeProfile.id
|
||||
SignalStore.notificationProfileValues().lastProfilePopupTime = System.currentTimeMillis()
|
||||
if (previousTopToastPopup?.isShowing == true) {
|
||||
previousTopToastPopup?.dismiss()
|
||||
}
|
||||
var view = requireView() as ViewGroup
|
||||
val fragment = parentFragmentManager.findFragmentByTag(BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
|
||||
if (fragment != null && fragment.isAdded && fragment.view != null) {
|
||||
view = fragment.requireView() as ViewGroup
|
||||
}
|
||||
try {
|
||||
previousTopToastPopup = show(view, R.drawable.ic_moon_16, getString(R.string.ConversationListFragment__s_on, activeProfile.name))
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Unable to show toast popup", e)
|
||||
}
|
||||
}, 500L)
|
||||
}
|
||||
notificationProfileStatus.visibility = View.VISIBLE
|
||||
} else {
|
||||
notificationProfileStatus.visibility = View.GONE
|
||||
}
|
||||
if (!SignalStore.notificationProfileValues().hasSeenTooltip && Util.hasItems(notificationProfiles)) {
|
||||
val target: View? = findOverflowMenuButton(_toolbar)
|
||||
if (target != null) {
|
||||
TooltipPopup.forTarget(target)
|
||||
.setText(R.string.ConversationListFragment__turn_your_notification_profile_on_or_off_here)
|
||||
.setBackgroundTint(ContextCompat.getColor(requireContext(), R.color.signal_button_primary))
|
||||
.setTextColor(ContextCompat.getColor(requireContext(), R.color.signal_button_primary_text))
|
||||
.setOnDismissListener { SignalStore.notificationProfileValues().hasSeenTooltip = true }
|
||||
.show(TooltipPopup.POSITION_BELOW)
|
||||
} else {
|
||||
Log.w(TAG, "Unable to find overflow menu to show Notification Profile tooltip")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findOverflowMenuButton(viewGroup: Toolbar): View? {
|
||||
return viewGroup.children.find { it is ActionMenuView }
|
||||
}
|
||||
|
||||
private inner class DestinationChangedListener : NavController.OnDestinationChangedListener {
|
||||
override fun onDestinationChanged(controller: NavController, destination: NavDestination, arguments: Bundle?) {
|
||||
when (destination.id) {
|
||||
R.id.conversationListFragment -> {
|
||||
presentToolbarForConversationListFragment()
|
||||
}
|
||||
R.id.conversationListArchiveFragment -> {
|
||||
presentToolbarForConversationListArchiveFragment()
|
||||
}
|
||||
R.id.storiesLandingFragment -> {
|
||||
presentToolbarForStoriesLandingFragment()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,14 +3,17 @@ package org.thoughtcrime.securesms.stories.landing
|
|||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.thoughtcrime.securesms.MainNavigator
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
|
@ -34,13 +37,7 @@ import org.thoughtcrime.securesms.util.visible
|
|||
/**
|
||||
* The "landing page" for Stories.
|
||||
*/
|
||||
class StoriesLandingFragment :
|
||||
DSLSettingsFragment(
|
||||
layoutId = R.layout.stories_landing_fragment,
|
||||
menuId = R.menu.story_landing_menu,
|
||||
titleId = R.string.ConversationListTabs__stories
|
||||
),
|
||||
MainNavigator.BackHandler {
|
||||
class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_landing_fragment) {
|
||||
|
||||
private lateinit var emptyNotice: View
|
||||
private lateinit var cameraFab: View
|
||||
|
@ -55,6 +52,16 @@ class StoriesLandingFragment :
|
|||
|
||||
private val tabsViewModel: ConversationListTabsViewModel by viewModels(ownerProducer = { requireActivity() })
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
menu.clear()
|
||||
inflater.inflate(R.menu.story_landing_menu, menu)
|
||||
}
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
StoriesLandingItem.register(adapter)
|
||||
MyStoriesItem.register(adapter)
|
||||
|
@ -79,6 +86,15 @@ class StoriesLandingFragment :
|
|||
adapter.submitList(getConfiguration(it).toMappingModelList())
|
||||
emptyNotice.visible = it.hasNoStories
|
||||
}
|
||||
|
||||
requireActivity().onBackPressedDispatcher.addCallback(
|
||||
viewLifecycleOwner,
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
tabsViewModel.onChatsSelected()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: StoriesLandingState): DSLConfiguration {
|
||||
|
@ -182,11 +198,6 @@ class StoriesLandingFragment :
|
|||
.show()
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
tabsViewModel.onChatsSelected()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return if (item.itemId == R.id.action_settings) {
|
||||
startActivity(StorySettingsActivity.getIntent(requireContext()))
|
||||
|
|
|
@ -47,6 +47,8 @@ class ConversationListTabsFragment : Fragment(R.layout.conversation_list_tabs) {
|
|||
|
||||
storiesUnreadIndicator.visible = state.unreadStoriesCount > 0
|
||||
storiesUnreadIndicator.text = formatCount(state.unreadStoriesCount)
|
||||
|
||||
requireView().visible = !state.isSearchOpen
|
||||
}
|
||||
|
||||
private fun formatCount(count: Long): String {
|
||||
|
|
|
@ -3,5 +3,6 @@ package org.thoughtcrime.securesms.stories.tabs
|
|||
data class ConversationListTabsState(
|
||||
val tab: ConversationListTab = ConversationListTab.CHATS,
|
||||
val unreadChatsCount: Long = 0L,
|
||||
val unreadStoriesCount: Long = 0L
|
||||
val unreadStoriesCount: Long = 0L,
|
||||
val isSearchOpen: Boolean = false
|
||||
)
|
||||
|
|
|
@ -35,6 +35,14 @@ class ConversationListTabsViewModel(repository: ConversationListTabRepository) :
|
|||
store.update { it.copy(tab = ConversationListTab.STORIES) }
|
||||
}
|
||||
|
||||
fun onSearchOpened() {
|
||||
store.update { it.copy(isSearchOpen = true) }
|
||||
}
|
||||
|
||||
fun onSearchClosed() {
|
||||
store.update { it.copy(isSearchOpen = false) }
|
||||
}
|
||||
|
||||
class Factory(private val repository: ConversationListTabRepository) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return modelClass.cast(ConversationListTabsViewModel(repository)) as T
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/toolbar_basic"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -10,4 +9,5 @@
|
|||
android:theme="?attr/actionBarStyle"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:navigationIcon="@drawable/ic_arrow_left_24"
|
||||
app:titleTextAppearance="@style/TextSecure.TitleTextStyle" />
|
||||
|
|
|
@ -14,160 +14,18 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:inflatedId="@+id/voice_note_player"
|
||||
android:layout="@layout/voice_note_player_stub"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier" />
|
||||
|
||||
<org.thoughtcrime.securesms.util.views.DarkOverflowToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/signal_background_primary"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarStyle"
|
||||
android:visibility="gone"
|
||||
app:contentInsetStart="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/toolbar_icon"
|
||||
android:layout_width="@dimen/toolbar_avatar_size"
|
||||
android:layout_height="@dimen/toolbar_avatar_size"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginStart="@dimen/toolbar_avatar_margin"
|
||||
android:contentDescription="@string/conversation_list_settings_shortcut"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/ic_contact_picture" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/toolbar_badge"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:badge_size="small"
|
||||
app:layout_constraintStart_toStartOf="@id/toolbar_icon"
|
||||
app:layout_constraintTop_toTopOf="@id/toolbar_icon" />
|
||||
|
||||
<View
|
||||
android:id="@+id/toolbar_settings_touch_area"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/toolbar_icon"
|
||||
app:layout_constraintStart_toStartOf="@id/toolbar_icon"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/unread_payments_indicator"
|
||||
android:layout_width="13dp"
|
||||
android:layout_height="13dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:alpha="0"
|
||||
android:background="@drawable/unread_count_background"
|
||||
app:layout_constraintBottom_toBottomOf="@id/toolbar_icon"
|
||||
app:layout_constraintStart_toStartOf="@id/toolbar_icon"
|
||||
tools:alpha="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/conversation_list_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="26dp"
|
||||
android:text="@string/app_name"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/signal_text_primary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/conversation_list_notification_profile_status"
|
||||
app:layout_constraintStart_toEndOf="@id/toolbar_icon"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/conversation_list_notification_profile_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:paddingHorizontal="3dp"
|
||||
android:paddingVertical="11dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/conversation_list_proxy_status"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_list_title"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_notification_profile_active"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/conversation_list_proxy_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:padding="12dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/search_action"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_list_notification_profile_status"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/ic_proxy_connected_24"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/search_action"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?actionBarItemBackground"
|
||||
android:contentDescription="@string/conversation_list_search_description"
|
||||
android:padding="12dp"
|
||||
android:tint="@color/signal_icon_tint_primary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_search_24" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</org.thoughtcrime.securesms.util.views.DarkOverflowToolbar>
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/toolbar_basic"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:layout="@layout/conversation_list_archive_toolbar"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/search_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout="@layout/conversation_list_search_toolbar"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/toolbar_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="toolbar,toolbar_basic" />
|
||||
|
||||
<View
|
||||
android:id="@+id/conversation_list_toolbar_shadow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="5dp"
|
||||
android:background="@drawable/toolbar_shadow"
|
||||
android:visibility="gone"
|
||||
android:elevation="100dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
|
@ -180,7 +38,7 @@
|
|||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@string/SearchFragment_no_results" />
|
||||
|
||||
<ViewStub
|
||||
|
@ -191,7 +49,7 @@
|
|||
android:layout="@layout/conversation_list_empty_state"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/reminder"
|
||||
|
@ -199,7 +57,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:inflatedId="@+id/reminder"
|
||||
android:layout="@layout/conversation_list_reminder_view"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/payments_notification"
|
||||
|
@ -207,7 +65,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:inflatedId="@+id/payments_notification"
|
||||
android:layout="@layout/payment_notification_view"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/banner_barrier"
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:name="org.thoughtcrime.securesms.main.MainActivityListHostFragment"
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.thoughtcrime.securesms.util.views.DarkOverflowToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/signal_background_primary"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarStyle"
|
||||
android:visibility="gone"
|
||||
app:contentInsetStart="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/toolbar_icon"
|
||||
android:layout_width="@dimen/toolbar_avatar_size"
|
||||
android:layout_height="@dimen/toolbar_avatar_size"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginStart="@dimen/toolbar_avatar_margin"
|
||||
android:contentDescription="@string/conversation_list_settings_shortcut"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/ic_contact_picture" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/toolbar_badge"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:badge_size="small"
|
||||
app:layout_constraintStart_toStartOf="@id/toolbar_icon"
|
||||
app:layout_constraintTop_toTopOf="@id/toolbar_icon" />
|
||||
|
||||
<View
|
||||
android:id="@+id/toolbar_settings_touch_area"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/toolbar_icon"
|
||||
app:layout_constraintStart_toStartOf="@id/toolbar_icon"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/unread_payments_indicator"
|
||||
android:layout_width="13dp"
|
||||
android:layout_height="13dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:alpha="0"
|
||||
android:background="@drawable/unread_count_background"
|
||||
app:layout_constraintBottom_toBottomOf="@id/toolbar_icon"
|
||||
app:layout_constraintStart_toStartOf="@id/toolbar_icon"
|
||||
tools:alpha="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/conversation_list_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="26dp"
|
||||
android:text="@string/app_name"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/signal_text_primary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/conversation_list_notification_profile_status"
|
||||
app:layout_constraintStart_toEndOf="@id/toolbar_icon"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/conversation_list_notification_profile_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:paddingHorizontal="3dp"
|
||||
android:paddingVertical="11dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/conversation_list_proxy_status"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_list_title"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_notification_profile_active"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/conversation_list_proxy_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:padding="12dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/search_action"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_list_notification_profile_status"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/ic_proxy_connected_24"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/search_action"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?actionBarItemBackground"
|
||||
android:contentDescription="@string/conversation_list_search_description"
|
||||
android:padding="12dp"
|
||||
android:tint="@color/signal_icon_tint_primary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_search_24" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</org.thoughtcrime.securesms.util.views.DarkOverflowToolbar>
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/toolbar_basic"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:layout="@layout/conversation_list_archive_toolbar"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/search_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout="@layout/conversation_list_search_toolbar"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/toolbar_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="toolbar,toolbar_basic" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fragment_container"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier"
|
||||
app:navGraph="@navigation/main_activity_list" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -4,16 +4,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.thoughtcrime.securesms.util.views.DarkOverflowToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:contentInsetStart="24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:title="@string/ConversationListTabs__stories" />
|
||||
|
||||
<View
|
||||
android:id="@+id/toolbar_shadow"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -22,7 +12,7 @@
|
|||
android:background="@drawable/toolbar_shadow"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler"
|
||||
|
@ -31,7 +21,7 @@
|
|||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton
|
||||
android:id="@+id/camera_fab"
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/main_activity_list"
|
||||
app:startDestination="@id/conversationListFragment">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/conversationListFragment"
|
||||
android:name="org.thoughtcrime.securesms.conversationlist.ConversationListFragment"
|
||||
android:label="conversation_list_fragment" >
|
||||
<action
|
||||
android:id="@+id/action_conversationListFragment_to_conversationListArchiveFragment"
|
||||
app:destination="@id/conversationListArchiveFragment" />
|
||||
<action
|
||||
android:id="@+id/action_conversationListFragment_to_storiesLandingFragment"
|
||||
app:destination="@id/storiesLandingFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/conversationListArchiveFragment"
|
||||
android:name="org.thoughtcrime.securesms.conversationlist.ConversationListArchiveFragment"
|
||||
android:label="conversation_list_archive_fragment" >
|
||||
<action
|
||||
android:id="@+id/action_conversationListArchiveFragment_to_storiesLandingFragment"
|
||||
app:destination="@id/storiesLandingFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/storiesLandingFragment"
|
||||
android:name="org.thoughtcrime.securesms.stories.landing.StoriesLandingFragment"
|
||||
android:label="stories_landing_fragment" />
|
||||
|
||||
</navigation>
|
Ładowanie…
Reference in New Issue