/** * Wire * Copyright (C) 2016 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.waz.zclient.pages.main.conversationpager; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.waz.api.ConversationsList; import com.waz.api.IConversation; import com.waz.api.SyncState; import com.waz.api.UpdateListener; import com.waz.api.User; import com.waz.zclient.OnBackPressedListener; import com.waz.zclient.R; import com.waz.zclient.controllers.navigation.NavigationController; import com.waz.zclient.controllers.navigation.Page; import com.waz.zclient.controllers.navigation.PagerControllerObserver; import com.waz.zclient.core.stores.connect.IConnectStore; import com.waz.zclient.core.stores.connect.InboxLinkConversation; import com.waz.zclient.core.stores.conversation.ConversationChangeRequester; import com.waz.zclient.core.stores.conversation.ConversationStoreObserver; import com.waz.zclient.pages.BaseFragment; import com.waz.zclient.pages.main.connect.ConnectRequestInboxManagerFragment; import com.waz.zclient.pages.main.connect.ConnectRequestLoadMode; import com.waz.zclient.pages.main.connect.PendingConnectRequestManagerFragment; import com.waz.zclient.pages.main.conversation.ConversationManagerFragment; import com.waz.zclient.ui.utils.MathUtils; import timber.log.Timber; public class SecondPageFragment extends BaseFragment<SecondPageFragment.Container> implements OnBackPressedListener, ConversationStoreObserver, ConversationManagerFragment.Container, PagerControllerObserver, PendingConnectRequestManagerFragment.Container, UpdateListener, ConnectRequestInboxManagerFragment.Container { public static final String TAG = SecondPageFragment.class.getName(); private static final String SECOND_PAGE_POSITION = "SECOND_PAGE_POSITION"; public static final String ARGUMENT_CONVERSATION_ID = "ARGUMENT_CONVERSATION_ID"; private Page currentPage; private IConversation selectedConversation; private IConversation.Type selectedConversationType; public static SecondPageFragment newInstance() { return new SecondPageFragment(); } ////////////////////////////////////////////////////////////////////////////////////////// // // LifeCycle // ////////////////////////////////////////////////////////////////////////////////////////// @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isAdded()) { Fragment fragment = getChildFragmentManager().findFragmentById(R.id.fl__second_page_container); if (fragment != null) { fragment.setUserVisibleHint(isVisibleToUser); } } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (savedInstanceState == null) { currentPage = Page.NONE; } else { int pos = savedInstanceState.getInt(SECOND_PAGE_POSITION); currentPage = Page.values()[pos]; } return inflater.inflate(R.layout.fragment_pager_second, container, false); } @Override public void onResume() { super.onResume(); getStoreFactory().getConversationStore().addConversationStoreObserverAndUpdate(this); getControllerFactory().getNavigationController().addPagerControllerObserver(this); } @Override public void onSaveInstanceState(Bundle outState) { outState.putInt(SECOND_PAGE_POSITION, currentPage.ordinal()); super.onSaveInstanceState(outState); } @Override public void onPause() { getControllerFactory().getNavigationController().removePagerControllerObserver(this); getStoreFactory().getConversationStore().removeConversationStoreObserver(this); super.onPause(); } @Override public void onDestroyView() { if (selectedConversation != null) { selectedConversation.removeUpdateListener(this); } selectedConversation = null; super.onDestroyView(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Fragment fragment = getChildFragmentManager().findFragmentById(R.id.fl__second_page_container); if (fragment != null) { fragment.onActivityResult(requestCode, resultCode, data); } } @Override public void onConversationListUpdated(@NonNull ConversationsList conversationsList) { } @Override public void onConversationListStateHasChanged(ConversationsList.ConversationsListState state) { } @Override public void onCurrentConversationHasChanged(IConversation fromConversation, final IConversation toConversation, final ConversationChangeRequester conversationChangerSender) { if (selectedConversation != null) { selectedConversation.removeUpdateListener(this); } selectedConversation = null; if (toConversation == null) { return; } if (fromConversation != null && fromConversation.getId().equals(toConversation.getId())) { return; } selectedConversation = toConversation; selectedConversation.addUpdateListener(this); selectedConversationType = toConversation.getType(); Timber.i("Conversation: %s type: %s requester: %s", toConversation, toConversation.getType(), conversationChangerSender); // either starting from beginning or switching fragment final boolean switchingToPendingConnectRequest = (toConversation.getType() == IConversation.Type.WAIT_FOR_CONNECTION); final boolean switchingToConnectRequestInbox = (toConversation instanceof InboxLinkConversation || toConversation.getId().equals(InboxLinkConversation.TAG) || toConversation.getType() == IConversation.Type.INCOMING_CONNECTION); // This must be posted because onCurrentConversationHasChanged() // might still be running and iterating over the observers - // while the posted call triggers things to register/unregister // from the list of observers, causing ConcurrentModificationException new Handler().post(new Runnable() { @Override public void run() { if (switchingToConnectRequestInbox) { Bundle arguments = new Bundle(); arguments.putString(ARGUMENT_CONVERSATION_ID, toConversation.getId()); openPage(Page.CONNECT_REQUEST_INBOX, arguments, conversationChangerSender); } else if (switchingToPendingConnectRequest) { Bundle arguments = new Bundle(); arguments.putString(ARGUMENT_CONVERSATION_ID, toConversation.getId()); openPage(Page.CONNECT_REQUEST_PENDING, arguments, conversationChangerSender); } else { openPage(Page.MESSAGE_STREAM, new Bundle(), conversationChangerSender); } } }); } @Override public void onConversationSyncingStateHasChanged(SyncState syncState) { } @Override public void onMenuConversationHasChanged(IConversation fromConversation) { } private void openPage(Page page, Bundle arguments, ConversationChangeRequester conversationChangerSender) { if (getContainer() == null || !isResumed()) { return; } Fragment fragment = getChildFragmentManager().findFragmentById(R.id.fl__second_page_container); if (currentPage != null && currentPage.equals(page)) { // Scroll to a certain connect request in inbox if (fragment instanceof ConnectRequestInboxManagerFragment) { ((ConnectRequestInboxManagerFragment) fragment).setVisibleConnectRequest(arguments); } if (page != Page.CONNECT_REQUEST_PENDING) { return; } } currentPage = page; FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); switch (getControllerFactory().getNavigationController().getCurrentPage()) { case CONVERSATION_LIST: transaction.setCustomAnimations(R.anim.message_fade_in, R.anim.message_fade_out, R.anim.message_fade_in, R.anim.message_fade_out); break; case CONNECT_REQUEST_INBOX: case CONNECT_REQUEST_PENDING: transaction.setCustomAnimations(R.anim.fragment_animation_second_page_slide_in_from_right, R.anim.fragment_animation_second_page_slide_out_to_left); break; } Fragment pageFragment; String tag; switch (page) { case CONNECT_REQUEST_PENDING: getControllerFactory().getNavigationController().setRightPage(Page.PENDING_CONNECT_REQUEST_AS_CONVERSATION, TAG); pageFragment = PendingConnectRequestManagerFragment.newInstance(null, arguments.getString( ARGUMENT_CONVERSATION_ID), ConnectRequestLoadMode.LOAD_BY_CONVERSATION_ID, IConnectStore.UserRequester.CONVERSATION); tag = PendingConnectRequestManagerFragment.TAG; break; case CONNECT_REQUEST_INBOX: getControllerFactory().getNavigationController().setRightPage(Page.CONNECT_REQUEST_INBOX, TAG); pageFragment = ConnectRequestInboxManagerFragment.newInstance(arguments.getString( ARGUMENT_CONVERSATION_ID)); tag = ConnectRequestInboxManagerFragment.TAG; break; case MESSAGE_STREAM: getControllerFactory().getNavigationController().setRightPage(Page.MESSAGE_STREAM, TAG); pageFragment = ConversationManagerFragment.newInstance(); tag = ConversationManagerFragment.TAG; break; case NONE: default: return; } transaction.replace(R.id.fl__second_page_container, pageFragment, tag).commit(); } @Override public void onOpenUrl(String url) { getContainer().onOpenUrl(url); } @Override public boolean onBackPressed() { Fragment fragment = getChildFragmentManager().findFragmentById(R.id.fl__second_page_container); return fragment instanceof OnBackPressedListener && ((OnBackPressedListener) fragment).onBackPressed(); } ////////////////////////////////////////////////////////////////////////////////////////// // // PagerControllerObserver // ////////////////////////////////////////////////////////////////////////////////////////// @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (position == 0 || MathUtils.floatEqual(positionOffset, 0f)) { getView().setAlpha(1f); } else { getView().setAlpha((float) Math.pow(positionOffset, 4)); } } @Override public void onPageSelected(int position) { // TO CONVERSATION LIST if (position == NavigationController.FIRST_PAGE) { getControllerFactory().getOnboardingController().incrementSwipeToConversationListCount(getControllerFactory().getNavigationController().getCurrentRightPage()); } } @Override public void onPageScrollStateChanged(int state) { } ////////////////////////////////////////////////////////////////////////////////////////// // // UserProfile // ////////////////////////////////////////////////////////////////////////////////////////// @Override public void onAcceptedConnectRequest(IConversation conversation) { getStoreFactory().getConversationStore().setCurrentConversation(conversation, ConversationChangeRequester.CONVERSATION_LIST); } @Override public void onAcceptedPendingOutgoingConnectRequest(IConversation conversation) { getStoreFactory().getConversationStore().setCurrentConversation(conversation, ConversationChangeRequester.CONNECT_REQUEST_ACCEPTED); } ////////////////////////////////////////////////////////////////////////////////////////// // // ConnectRequestInboxManagerFragment.Container // ////////////////////////////////////////////////////////////////////////////////////////// @Override public void dismissInboxFragment() { getControllerFactory().getNavigationController().setVisiblePage(Page.CONVERSATION_LIST, TAG); } @Override public void onAcceptedUser(IConversation conversation) { getControllerFactory().getNavigationController().setVisiblePage(Page.CONVERSATION_LIST, TAG); } ////////////////////////////////////////////////////////////////////////////////////////// // // UpdateListener // ////////////////////////////////////////////////////////////////////////////////////////// @Override public void updated() { if ((selectedConversationType == IConversation.Type.INCOMING_CONNECTION || selectedConversationType == IConversation.Type.WAIT_FOR_CONNECTION) && selectedConversation.getType() == IConversation.Type.ONE_TO_ONE) { openPage(Page.MESSAGE_STREAM, new Bundle(), ConversationChangeRequester.CONNECT_REQUEST_ACCEPTED); } selectedConversationType = selectedConversation.getType(); } @Override public void onPagerEnabledStateHasChanged(boolean enabled) { } @Override public void dismissUserProfile() { } @Override public void dismissSingleUserProfile() { } @Override public void showRemoveConfirmation(User user) { } public interface Container { void onOpenUrl(String url); } }