/**
* 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.participants;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.TextView;
import com.waz.api.NetworkMode;
import com.waz.api.User;
import com.waz.api.Verification;
import com.waz.zclient.BaseActivity;
import com.waz.zclient.OnBackPressedListener;
import com.waz.zclient.R;
import com.waz.zclient.controllers.confirmation.ConfirmationCallback;
import com.waz.zclient.controllers.confirmation.ConfirmationRequest;
import com.waz.zclient.controllers.confirmation.IConfirmationController;
import com.waz.zclient.controllers.confirmation.TwoButtonConfirmationCallback;
import com.waz.zclient.controllers.navigation.NavigationController;
import com.waz.zclient.controllers.tracking.events.connect.BlockingEvent;
import com.waz.zclient.core.stores.connect.IConnectStore;
import com.waz.zclient.core.stores.conversation.ConversationChangeRequester;
import com.waz.zclient.core.stores.network.NetworkAction;
import com.waz.zclient.core.stores.singleparticipants.SingleParticipantStoreObserver;
import com.waz.zclient.media.SoundController;
import com.waz.zclient.pages.BaseFragment;
import com.waz.zclient.pages.main.connect.UserProfile;
import com.waz.zclient.pages.main.connect.UserProfileContainer;
import com.waz.zclient.pages.main.participants.dialog.DialogLaunchMode;
import com.waz.zclient.tracking.GlobalTrackingController;
import com.waz.zclient.ui.animation.fragment.FadeAnimation;
import com.waz.zclient.ui.theme.OptionsTheme;
import com.waz.zclient.ui.theme.ThemeUtils;
import com.waz.zclient.ui.views.UserDetailsView;
import com.waz.zclient.ui.views.e2ee.ShieldView;
import com.waz.zclient.utils.LayoutSpec;
import com.waz.zclient.utils.ViewUtils;
import com.waz.zclient.views.images.ImageAssetImageView;
import com.waz.zclient.views.menus.FooterMenu;
import com.waz.zclient.views.menus.FooterMenuCallback;
public class SingleParticipantFragment extends BaseFragment<SingleParticipantFragment.Container> implements
UserProfile,
SingleParticipantStoreObserver,
OnBackPressedListener,
TabbedParticipantBodyFragment.Container,
ParticipantBackbarFragment.Container {
public static final String TAG = SingleParticipantFragment.class.getName();
public static final String ARGUMENT_SHOWING_COMMON_USER = "ARGUMENT_SHOWING_COMMON_USER";
private static final String SAVE_STATE_OTHER_USER_PROFILE_SCREEN_WAS_TRACKED = "SAVE_STATE_OTHER_USER_PROFILE_SCREEN_WAS_TRACKED";
private static final String ARGUMENT_USER_REQUESTER = "ARGUMENT_USER_REQUESTER";
private TextView header;
private ShieldView shieldView;
private UserDetailsView userDetailsView;
private boolean isBelowUserProfile;
private boolean goToConversationWithUser;
private FooterMenu footerMenu;
private boolean otherUserProfileScreenWasTracked;
private ImageAssetImageView imageAssetImageViewProfile;
public static SingleParticipantFragment newInstance(boolean showingCommonUser,
IConnectStore.UserRequester userRequester) {
SingleParticipantFragment newFragment = new SingleParticipantFragment();
Bundle args = new Bundle();
args.putBoolean(ARGUMENT_SHOWING_COMMON_USER, showingCommonUser);
args.putSerializable(ARGUMENT_USER_REQUESTER, userRequester);
newFragment.setArguments(args);
return newFragment;
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Lifecycle
//
//////////////////////////////////////////////////////////////////////////////////////////
@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
Animation animation = super.onCreateAnimation(transit, enter, nextAnim);
if (getControllerFactory().getConversationScreenController().getPopoverLaunchMode() != DialogLaunchMode.AVATAR &&
getControllerFactory().getConversationScreenController().getPopoverLaunchMode() != DialogLaunchMode.COMMON_USER) {
int centerX = ViewUtils.getOrientationIndependentDisplayWidth(getActivity()) / 2;
int centerY = ViewUtils.getOrientationIndependentDisplayHeight(getActivity()) / 2;
int duration;
int delay = 0;
// Fade out animation when starting conversation directly with this user
if (goToConversationWithUser && !enter) {
goToConversationWithUser = false;
duration = getResources().getInteger(R.integer.framework_animation_duration_medium);
animation = new FadeAnimation(duration, 1, 0);
} else {
if (isBelowUserProfile) {
if (LayoutSpec.isTablet(getActivity())) {
animation = new ProfileTabletAnimation(enter,
getResources().getInteger(R.integer.framework_animation_duration_long),
-getResources().getDimensionPixelSize(R.dimen.participant_dialog__initial_width));
} else {
if (enter) {
isBelowUserProfile = false;
duration = getResources().getInteger(R.integer.reopen_profile_source__animation_duration);
delay = getResources().getInteger(R.integer.reopen_profile_source__delay);
} else {
duration = getResources().getInteger(R.integer.reopen_profile_source__animation_duration);
}
animation = new ProfileSourceAnimation(enter, duration, delay, centerX, centerY);
}
} else if (nextAnim != 0) {
if (LayoutSpec.isTablet(getActivity())) {
animation = new ProfileTabletAnimation(enter,
getResources().getInteger(R.integer.framework_animation_duration_long),
getResources().getDimensionPixelSize(R.dimen.participant_dialog__initial_width));
} else {
if (enter) {
duration = getResources().getInteger(R.integer.open_profile__animation_duration);
delay = getResources().getInteger(R.integer.open_profile__delay);
} else {
duration = getResources().getInteger(R.integer.close_profile__animation_duration);
}
animation = new ProfileAnimation(enter, duration, delay, centerX, centerY);
}
}
}
}
return animation;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_participants_single, viewGroup, false);
Toolbar toolbar = ViewUtils.getView(view, R.id.t__single_participant__toolbar);
shieldView = ViewUtils.getView(view, R.id.sv__otr__verified_shield);
shieldView.setVisibility(View.GONE);
Bundle args = getArguments();
IConnectStore.UserRequester requester = null;
if (args != null) {
requester = (IConnectStore.UserRequester) args.getSerializable(ARGUMENT_USER_REQUESTER);
}
header = ViewUtils.getView(view, R.id.tv__single_participant__toolbar__title);
userDetailsView = ViewUtils.getView(view, R.id.udv__single_participant__user_details);
footerMenu = ViewUtils.getView(view, R.id.upm__footer);
imageAssetImageViewProfile = ViewUtils.getView(view, R.id.iaiv__single_participant);
imageAssetImageViewProfile.setDisplayType(ImageAssetImageView.DisplayType.CIRCLE);
if (requester == IConnectStore.UserRequester.PARTICIPANTS) {
footerMenu.setVisibility(View.GONE);
imageAssetImageViewProfile.setVisibility(View.GONE);
getChildFragmentManager().beginTransaction()
.add(R.id.fl__participant__tab__container,
TabbedParticipantBodyFragment.newInstance(TabbedParticipantBodyFragment.USER_PAGE),
TabbedParticipantBodyFragment.TAG)
.commit();
// Posting so that we can get height after onMeasure has been called
view.post(new Runnable() {
@Override
public void run() {
View header = ViewUtils.getView(view, R.id.ll__single_participant__header_container);
View tabContainer = ViewUtils.getView(view, R.id.fl__participant__tab__container);
if (header == null || tabContainer == null) {
return;
}
int height = header.getHeight();
tabContainer.setPadding(0, height, 0, 0);
}
});
}
View backgroundContainer = ViewUtils.getView(view, R.id.fl__send_connect_request__background_container);
if ((LayoutSpec.isPhone(getActivity()) && getControllerFactory().getNavigationController().getPagerPosition() == NavigationController.FIRST_PAGE) ||
(getControllerFactory().getConversationScreenController().getPopoverLaunchMode() == DialogLaunchMode.AVATAR ||
getControllerFactory().getConversationScreenController().getPopoverLaunchMode() == DialogLaunchMode.COMMON_USER)) {
backgroundContainer.setClickable(true);
} else {
backgroundContainer.setBackgroundColor(Color.TRANSPARENT);
}
if (ThemeUtils.isDarkTheme(getContext())) {
toolbar.setNavigationIcon(R.drawable.action_back_light);
} else {
toolbar.setNavigationIcon(R.drawable.action_back_dark);
}
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getContainer().dismissSingleUserProfile();
}
});
// Hide footer until user is loaded
footerMenu.setVisibility(View.GONE);
if (savedInstanceState == null) {
otherUserProfileScreenWasTracked = false;
} else {
otherUserProfileScreenWasTracked = savedInstanceState.getBoolean(SAVE_STATE_OTHER_USER_PROFILE_SCREEN_WAS_TRACKED);
}
return view;
}
@Override
public void onStart() {
super.onStart();
getStoreFactory().getSingleParticipantStore().addSingleParticipantObserver(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putBoolean(SAVE_STATE_OTHER_USER_PROFILE_SCREEN_WAS_TRACKED, otherUserProfileScreenWasTracked);
super.onSaveInstanceState(outState);
}
@Override
public void onStop() {
getStoreFactory().getSingleParticipantStore().removeSingleParticipantObserver(this);
super.onStop();
}
@Override
public void onDestroyView() {
if (getContainer() != null &&
!getControllerFactory().isTornDown()) {
getControllerFactory().getSingleImageController().clearReferences();
}
imageAssetImageViewProfile = null;
header = null;
footerMenu = null;
super.onDestroyView();
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// UserProfile
//
//////////////////////////////////////////////////////////////////////////////////////////
@Override
public void isBelowUserProfile(boolean isBelow) {
isBelowUserProfile = isBelow;
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// SingleParticipantStoreObserver
//
//////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onUserUpdated(final User user) {
if (user == null) {
return;
}
imageAssetImageViewProfile.connectImageAsset(user.getPicture());
header.setText(user.getDisplayName());
userDetailsView.setUser(user);
shieldView.setVisibility(user.getVerified() == Verification.VERIFIED ? View.VISIBLE : View.GONE);
// Show footer if profile is not for self user
if (!user.isMe()) {
if (!otherUserProfileScreenWasTracked) {
otherUserProfileScreenWasTracked = true;
}
final boolean showingCommonUser = getArguments().getBoolean(ARGUMENT_SHOWING_COMMON_USER);
final boolean ignoreRightClick = getArguments().getSerializable(ARGUMENT_USER_REQUESTER) == IConnectStore.UserRequester.CALL;
if (ignoreRightClick) {
footerMenu.setRightActionText("");
} else if (showingCommonUser) {
footerMenu.setRightActionText(getResources().getString(R.string.glyph__block));
}
footerMenu.setCallback(new FooterMenuCallback() {
@Override
public void onLeftActionClicked() {
getControllerFactory().getConversationScreenController().hideParticipants(true, false);
// Go to conversation with this user
goToConversationWithUser = true;
getContainer().dismissUserProfile();
getStoreFactory().getConversationStore().setCurrentConversation(user.getConversation(),
ConversationChangeRequester.START_CONVERSATION);
}
@Override
public void onRightActionClicked() {
if (ignoreRightClick) {
return;
}
if (showingCommonUser) {
showBlockConfirmation(user);
} else {
getStoreFactory().getNetworkStore().doIfHasInternetOrNotifyUser(new NetworkAction() {
@Override
public void execute(NetworkMode networkMode) {
getContainer().showRemoveConfirmation(user);
}
@Override
public void onNoNetwork() {
ViewUtils.showAlertDialog(getActivity(),
R.string.alert_dialog__no_network__header,
R.string.remove_from_conversation__no_network__message,
R.string.alert_dialog__confirmation,
null, true);
}
});
}
}
});
if (getArguments().getSerializable(ARGUMENT_USER_REQUESTER) != IConnectStore.UserRequester.PARTICIPANTS) {
footerMenu.setVisibility(View.VISIBLE);
}
}
}
private void showBlockConfirmation(final User user) {
ConfirmationCallback callback = new TwoButtonConfirmationCallback() {
@Override
public void positiveButtonClicked(boolean checkboxIsSelected) {
getStoreFactory().getConnectStore().blockUser(user);
// Dismiss common user profile
getContainer().dismissUserProfile();
((BaseActivity) getActivity()).injectJava(GlobalTrackingController.class).tagEvent(new BlockingEvent(BlockingEvent.ConformationResponse.BLOCK));
}
@Override
public void negativeButtonClicked() {
((BaseActivity) getActivity()).injectJava(GlobalTrackingController.class).tagEvent(new BlockingEvent(BlockingEvent.ConformationResponse.CANCEL));
}
@Override
public void onHideAnimationEnd(boolean confirmed, boolean canceled, boolean checkboxIsSelected) {
}
};
String header = getString(R.string.confirmation_menu__block_header);
String text = getString(R.string.confirmation_menu__block_text_with_name, user.getDisplayName());
String confirm = getString(R.string.confirmation_menu__confirm_block);
String cancel = getString(R.string.confirmation_menu__cancel);
OptionsTheme optionsTheme = getControllerFactory().getThemeController().getThemeDependentOptionsTheme();
ConfirmationRequest request = new ConfirmationRequest.Builder()
.withHeader(header)
.withMessage(text)
.withPositiveButton(confirm)
.withNegativeButton(cancel)
.withConfirmationCallback(callback)
.withWireTheme(optionsTheme)
.build();
getControllerFactory().getConfirmationController().requestConfirmation(request, IConfirmationController.USER_PROFILE);
SoundController ctrl = inject(SoundController.class);
if (ctrl != null) {
ctrl.playAlert();
}
}
@Override
public boolean onBackPressed() {
return false;
}
@Override
public void showRemoveConfirmation(User user) {
getContainer().showRemoveConfirmation(user);
}
@Override
public void onOpenUrl(String url) {
getContainer().onOpenUrl(url);
}
public interface Container extends UserProfileContainer {
void onOpenUrl(String url);
}
}