/**
* 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.controllers.navigation;
import android.content.Context;
import android.os.Bundle;
import android.util.Property;
import com.waz.zclient.R;
import com.waz.zclient.pages.main.calling.enums.VoiceBarAppearance;
import com.waz.zclient.utils.LayoutSpec;
import timber.log.Timber;
import java.util.HashSet;
import java.util.Set;
public class NavigationController implements INavigationController {
public static final String TAG = NavigationController.class.getName();
public static final int FIRST_PAGE = 0;
public static final int SECOND_PAGE = 1;
private static final String SAVED_INSTANCE_CURRENT_PAGER_POSITION = "SAVED_INSTANCE_CURRENT_PAGER_POSITION";
private static final String SAVED_INSTANCE_CURRENT_PAGE = "SAVED_INSTANCE_CURRENT_PAGE";
private static final String SAVED_INSTANCE_CURRENT_LEFT_PAGE = "SAVED_INSTANCE_CURRENT_LEFT_PAGE";
private static final String SAVED_INSTANCE_CURRENT_RIGHT_PAGE = "SAVED_INSTANCE_CURRENT_RIGHT_PAGE";
private static final String SAVED_INSTANCE_VOICE_BAR_APPEARANCE_CONVERSATION_LIST = "SAVED_INSTANCE_VOICE_BAR_APPEARANCE_CONVERSATION_LIST";
private static final String SAVED_INSTANCE_VOICE_BAR_APPEARANCE_MESSAGE_STREAM = "SAVED_INSTANCE_VOICE_BAR_APPEARANCE_MESSAGE_STREAM";
private static final String SAVED_INSTANCE_SCREEN_OFFSET_X = "SAVED_INSTANCE_SCREEN_OFFSET_X";
private static final String SAVED_INSTANCE_SCREEN_OFFSET_Y = "SAVED_INSTANCE_SCREEN_OFFSET_Y";
private static final String SAVED_INSTANCE_PAGER_ENABLE_STATE = "SAVED_INSTANCE_PAGER_ENABLE_STATE";
public static final Property<INavigationController, Integer> SCREEN_OFFSET_Y = new Property<INavigationController, Integer>(Integer.class, "screenOffsetY") {
@Override
public Integer get(INavigationController object) {
return object.getScreenOffsetY();
}
@Override
public void set(INavigationController object, Integer value) {
object.setScreenOffsetY(value);
}
};
public static final String PAGER_TAG = "Pager";
private final int maxOffsetX;
private final int maxOffsetY;
private int screenOffsetX;
private int screenOffsetY;
private Set<NavigationControllerObserver> navigationControllerObservers;
private Set<PagerControllerObserver> pagerControllerObservers;
private Set<ScreenPositionObserver> screenPositionObservers;
private Page currentPage;
private Page lastPageLeft;
private Page lastPageRight;
private int currentPagerPos;
private VoiceBarAppearance voiceBarAppearanceConversationList;
private VoiceBarAppearance voiceBarAppearanceMessageStream;
private boolean isPagerEnabled;
private boolean isInLandscape;
private boolean isPhone;
private boolean wasPaused;
@Override
public void addNavigationControllerObserver(NavigationControllerObserver navigationControllerObserver) {
navigationControllerObservers.add(navigationControllerObserver);
navigationControllerObserver.onPageVisible(currentPage);
}
@Override
public void removeNavigationControllerObserver(NavigationControllerObserver navigationControllerObserver) {
navigationControllerObservers.remove(navigationControllerObserver);
}
@Override
public void addPagerControllerObserver(PagerControllerObserver pagerControllerObserver) {
pagerControllerObservers.add(pagerControllerObserver);
}
@Override
public void removePagerControllerObserver(PagerControllerObserver pagerControllerObserver) {
pagerControllerObservers.remove(pagerControllerObserver);
}
@Override
public void addScreenPositionObserver(ScreenPositionObserver screenPositionObserver) {
screenPositionObservers.add(screenPositionObserver);
screenPositionObserver.onScreenPositionChanged(screenOffsetX, screenOffsetY);
}
@Override
public void removeScreenPositionObserver(ScreenPositionObserver screenPositionObserver) {
screenPositionObservers.remove(screenPositionObserver);
}
public NavigationController(Context context) {
isPhone = LayoutSpec.isPhone(context);
maxOffsetX = context.getResources().getDimensionPixelSize(R.dimen.background__max_offset_x);
maxOffsetY = context.getResources().getDimensionPixelSize(R.dimen.background__max_offset_y);
navigationControllerObservers = new HashSet<>();
pagerControllerObservers = new HashSet<>();
screenPositionObservers = new HashSet<>();
currentPage = Page.START;
lastPageLeft = Page.START;
lastPageRight = Page.START;
currentPagerPos = FIRST_PAGE;
voiceBarAppearanceConversationList = VoiceBarAppearance.MICRO;
voiceBarAppearanceMessageStream = VoiceBarAppearance.FULL;
}
@Override
public VoiceBarAppearance getVoiceBarAppearanceConversationList() {
return voiceBarAppearanceConversationList;
}
@Override
public VoiceBarAppearance getVoiceBarAppearanceMessageStream() {
return voiceBarAppearanceMessageStream;
}
@Override
public void setConversationListState(VoiceBarAppearance voiceBarAppearance) {
if (voiceBarAppearanceConversationList == voiceBarAppearance) {
return;
}
voiceBarAppearanceConversationList = voiceBarAppearance;
if (currentPage == Page.CONVERSATION_LIST) {
for (NavigationControllerObserver navigationControllerObserver : navigationControllerObservers) {
navigationControllerObserver.onPageStateHasChanged(Page.CONVERSATION_LIST);
}
}
}
@Override
public void setMessageStreamState(VoiceBarAppearance voiceBarAppearance) {
if (voiceBarAppearanceMessageStream == voiceBarAppearance) {
return;
}
voiceBarAppearanceMessageStream = voiceBarAppearance;
if (currentPage == Page.MESSAGE_STREAM) {
for (NavigationControllerObserver navigationControllerObserver : navigationControllerObservers) {
navigationControllerObserver.onPageStateHasChanged(Page.MESSAGE_STREAM);
}
}
}
@Override
public void setVisiblePage(Page page, String sender) {
Timber.i("Page: %s Sender: %s", page, sender);
if (currentPage == page && !isInLandscape) {
return;
}
currentPage = page;
for (NavigationControllerObserver navigationControllerObserver : navigationControllerObservers) {
navigationControllerObserver.onPageVisible(page);
}
}
@Override
public void setPagerPosition(int position) {
if (currentPagerPos == position) {
return;
}
currentPagerPos = position;
if (currentPagerPos == 0) {
setVisiblePage(lastPageLeft, PAGER_TAG);
} else {
setVisiblePage(lastPageRight, PAGER_TAG);
}
}
@Override
public int getPagerPosition() {
return currentPagerPos;
}
@Override
public void resetPagerPositionToDefault() {
currentPagerPos = FIRST_PAGE;
}
@Override
public void setLeftPage(Page leftPage, String sender) {
lastPageLeft = leftPage;
if (isPhone) {
if (currentPagerPos == FIRST_PAGE) {
setVisiblePage(leftPage, sender);
}
} else {
if (currentPagerPos == FIRST_PAGE || isInLandscape) {
setVisiblePage(leftPage, sender);
}
}
}
@Override
public void setRightPage(Page rightPage, String sender) {
lastPageRight = rightPage;
if (isPhone) {
if (currentPagerPos == SECOND_PAGE) {
setVisiblePage(rightPage, sender);
}
} else {
if (currentPagerPos == SECOND_PAGE || isInLandscape) {
setVisiblePage(rightPage, sender);
}
}
}
@Override
public Page getCurrentPage() {
return currentPage;
}
@Override
public Page getCurrentLeftPage() {
return lastPageLeft;
}
@Override
public Page getCurrentRightPage() {
return lastPageRight;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
currentPagerPos = savedInstanceState.getInt(SAVED_INSTANCE_CURRENT_PAGER_POSITION);
currentPage = Page.values()[savedInstanceState.getInt(SAVED_INSTANCE_CURRENT_PAGE)];
lastPageLeft = Page.values()[savedInstanceState.getInt(SAVED_INSTANCE_CURRENT_LEFT_PAGE)];
lastPageRight = Page.values()[savedInstanceState.getInt(SAVED_INSTANCE_CURRENT_RIGHT_PAGE)];
voiceBarAppearanceMessageStream = VoiceBarAppearance.values()[savedInstanceState.getInt(
SAVED_INSTANCE_VOICE_BAR_APPEARANCE_MESSAGE_STREAM)];
voiceBarAppearanceConversationList = VoiceBarAppearance.values()[savedInstanceState.getInt(
SAVED_INSTANCE_VOICE_BAR_APPEARANCE_CONVERSATION_LIST)];
screenOffsetX = savedInstanceState.getInt(SAVED_INSTANCE_SCREEN_OFFSET_X);
screenOffsetY = savedInstanceState.getInt(SAVED_INSTANCE_SCREEN_OFFSET_Y);
isPagerEnabled = savedInstanceState.getBoolean(SAVED_INSTANCE_PAGER_ENABLE_STATE);
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(SAVED_INSTANCE_CURRENT_PAGER_POSITION, currentPagerPos);
outState.putInt(SAVED_INSTANCE_CURRENT_PAGE, currentPage.ordinal());
outState.putInt(SAVED_INSTANCE_CURRENT_LEFT_PAGE, lastPageLeft.ordinal());
outState.putInt(SAVED_INSTANCE_CURRENT_RIGHT_PAGE, lastPageRight.ordinal());
outState.putInt(SAVED_INSTANCE_VOICE_BAR_APPEARANCE_MESSAGE_STREAM, voiceBarAppearanceMessageStream.ordinal());
outState.putInt(SAVED_INSTANCE_VOICE_BAR_APPEARANCE_CONVERSATION_LIST,
voiceBarAppearanceConversationList.ordinal());
outState.putInt(SAVED_INSTANCE_SCREEN_OFFSET_X, screenOffsetX);
outState.putInt(SAVED_INSTANCE_SCREEN_OFFSET_Y, screenOffsetY);
outState.putBoolean(SAVED_INSTANCE_PAGER_ENABLE_STATE, isPagerEnabled);
}
@Override
public void setScreenOffsetX(int offset) {
if (offset > maxOffsetX) {
offset = maxOffsetX;
}
screenOffsetX = offset;
notifyScreenPositionHasChanged();
}
@Override
public void setScreenOffsetY(int offset) {
if (offset > maxOffsetY) {
offset = maxOffsetY;
}
screenOffsetY = offset;
notifyScreenPositionHasChanged();
}
@Override
public int getScreenOffsetX() {
return screenOffsetX;
}
@Override
public int getScreenOffsetY() {
return screenOffsetY;
}
@Override
public void setScreenOffsetYFactor(float factorY) {
if (factorY > 1) {
factorY = 1.0f;
}
setScreenOffsetY((int) (factorY * maxOffsetY));
}
@Override
public int getMaxScreenOffsetY() {
return maxOffsetY;
}
@Override
public void setPagerEnabled(boolean enabled) {
Timber.i("setPagerEnabled(%b)", enabled);
if (enabled && getCurrentRightPage() == Page.PARTICIPANT) {
Timber.i("ignoring setPagerEnabled()");
return;
}
isPagerEnabled = enabled;
for (PagerControllerObserver pagerControllerObserver : pagerControllerObservers) {
pagerControllerObserver.onPagerEnabledStateHasChanged(enabled);
}
}
@Override
public void setPagerSettingForPage(Page page) {
switch (page) {
case CONVERSATION_LIST:
if (isPhone) {
// Handled in ConversationListManagerFragment
return;
}
setPagerEnabled(true);
break;
case SELF_PROFILE_OVERLAY:
case CAMERA:
case CONFIRMATION_DIALOG:
case SINGLE_MESSAGE:
case DRAWING:
case SHARE_LOCATION:
case COLLECTION:
case ARCHIVE:
setPagerEnabled(false);
break;
case CONVERSATION_MENU_OVER_CONVERSATION_LIST:
case PARTICIPANT:
case PARTICIPANT_USER_PROFILE:
case PICK_USER:
case COMMON_USER_PROFILE:
case SEND_CONNECT_REQUEST:
case PENDING_CONNECT_REQUEST:
case BLOCK_USER:
case PICK_USER_ADD_TO_CONVERSATION:
if (isPhone) {
setPagerEnabled(false);
}
break;
default:
setPagerEnabled(true);
}
}
@Override
public boolean isPagerEnabled() {
return isPagerEnabled;
}
@Override
public void setIsLandscape(boolean isLandscape) {
this.isInLandscape = isLandscape;
}
@Override
public boolean isActivityResuming() {
return wasPaused;
}
@Override
public void markActivityPaused() {
wasPaused = true;
}
@Override
public void markActivityResumed() {
wasPaused = false;
}
@Override
public void tearDown() {
navigationControllerObservers.clear();
pagerControllerObservers.clear();
screenPositionObservers.clear();
currentPage = Page.START;
lastPageLeft = Page.START;
lastPageRight = Page.START;
currentPagerPos = FIRST_PAGE;
voiceBarAppearanceConversationList = VoiceBarAppearance.MICRO;
voiceBarAppearanceMessageStream = VoiceBarAppearance.FULL;
}
private void notifyScreenPositionHasChanged() {
for (ScreenPositionObserver screenPositionObserver : screenPositionObservers) {
screenPositionObserver.onScreenPositionChanged(screenOffsetX, screenOffsetY);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Pager
//
//////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
for (PagerControllerObserver pagerControllerObserver : pagerControllerObservers) {
pagerControllerObserver.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
float offset = 0;
switch (position) {
case 0:
offset = -(positionOffset * maxOffsetX);
break;
case 1:
offset = -maxOffsetX + (positionOffset * maxOffsetX);
break;
}
screenOffsetX = (int) offset;
notifyScreenPositionHasChanged();
}
@Override
public void onPageSelected(int position) {
for (PagerControllerObserver pagerControllerObserver : pagerControllerObservers) {
pagerControllerObserver.onPageSelected(position);
}
}
@Override
public void onPageScrollStateChanged(int state) {
for (PagerControllerObserver pagerControllerObserver : pagerControllerObservers) {
pagerControllerObserver.onPageScrollStateChanged(state);
}
}
private void log() {
Timber.i("leftPage: %s", lastPageLeft);
Timber.i("rightPage: %s", lastPageRight);
Timber.i("currentPage: %s", currentPage);
Timber.i("voiceBarAppearanceConversationList: %s", voiceBarAppearanceConversationList);
Timber.i("voiceBarAppearanceMessageStream: %s", voiceBarAppearanceMessageStream);
}
}