com.waz.zclient.pages.main.participants.ParticipantHeaderFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.waz.zclient.pages.main.participants.ParticipantHeaderFragment.java

Source

/**
 * 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.animation.ObjectAnimator;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.waz.api.CommonConnections;
import com.waz.api.IConversation;
import com.waz.api.Message;
import com.waz.api.MessagesList;
import com.waz.api.NetworkMode;
import com.waz.api.OtrClient;
import com.waz.api.User;
import com.waz.api.UsersList;
import com.waz.api.Verification;
import com.waz.zclient.R;
import com.waz.zclient.controllers.accentcolor.AccentColorObserver;
import com.waz.zclient.controllers.currentfocus.IFocusController;
import com.waz.zclient.controllers.globallayout.KeyboardVisibilityObserver;
import com.waz.zclient.core.stores.network.NetworkAction;
import com.waz.zclient.core.controllers.tracking.attributes.RangedAttribute;
import com.waz.zclient.core.stores.connect.ConnectStoreObserver;
import com.waz.zclient.core.stores.connect.IConnectStore;
import com.waz.zclient.core.stores.participants.ParticipantsStoreObserver;
import com.waz.zclient.pages.BaseFragment;
import com.waz.zclient.pages.main.conversation.controller.ConversationScreenControllerObserver;
import com.waz.zclient.pages.main.conversation.controller.IConversationScreenController;
import com.waz.zclient.ui.text.AccentColorEditText;
import com.waz.zclient.ui.utils.KeyboardUtils;
import com.waz.zclient.ui.utils.MathUtils;
import com.waz.zclient.ui.views.e2ee.ShieldView;
import com.waz.zclient.utils.LayoutSpec;
import com.waz.zclient.utils.ViewUtils;

public class ParticipantHeaderFragment extends BaseFragment<ParticipantHeaderFragment.Container>
        implements KeyboardVisibilityObserver, View.OnClickListener, ParticipantsStoreObserver,
        ConversationScreenControllerObserver, ConnectStoreObserver, AccentColorObserver {
    public static final String TAG = ParticipantHeaderFragment.class.getName();
    private static final String ARG_USER_REQUESTER = "ARG_USER_REQUESTER";

    private View headerTopBorder;
    private TextView subHeader;
    private TextView closeButton;
    private AccentColorEditText headerEditText;
    private TextView headerReadOnlyTextView;
    private LinearLayout textViewAddressBookNameContainer;
    private View bottomBorder;
    private TextView penIcon;
    // Helps center title in 1:1
    private ShieldView shieldView;
    private IConnectStore.UserRequester userRequester;

    private Handler penIconHandler;
    private Runnable penIconRunnable = new Runnable() {
        @Override
        public void run() {
            if (penIcon == null) {
                return;
            }
            showPenIcon(false);
        }
    };
    private boolean isGroupConversation;

    public static ParticipantHeaderFragment newInstance(IConnectStore.UserRequester userRequester) {
        ParticipantHeaderFragment participantHeaderFragment = new ParticipantHeaderFragment();
        Bundle args = new Bundle();
        args.putSerializable(ARG_USER_REQUESTER, userRequester);
        participantHeaderFragment.setArguments(args);
        return participantHeaderFragment;
    }

    @Override
    public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
        final Fragment parent = getParentFragment();

        // Apply the workaround only if this is a child fragment, and the parent
        // is being removed.
        if (!enter && parent != null && parent.isRemoving()) {
            // This is a workaround for the bug where child fragments disappear when
            // the parent is removed (as all children are first removed from the parent)
            // See https://code.google.com/p/android/issues/detail?id=55228
            Animation doNothingAnim = new AlphaAnimation(1, 1);
            doNothingAnim.setDuration(ViewUtils.getNextAnimationDuration(parent));
            return doNothingAnim;
        } else {
            return super.onCreateAnimation(transit, enter, nextAnim);
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        userRequester = (IConnectStore.UserRequester) args.getSerializable(ARG_USER_REQUESTER);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_participants_header, container, false);

        headerTopBorder = ViewUtils.getView(rootView, R.id.v_participants__header__top_border);
        subHeader = ViewUtils.getView(rootView, R.id.ttv__participants__sub_header);
        textViewAddressBookNameContainer = ViewUtils.getView(rootView,
                R.id.ll__single_participants__real_name__container);
        textViewAddressBookNameContainer.setVisibility(View.GONE);
        closeButton = ViewUtils.getView(rootView, R.id.gtv__participants__close);
        headerReadOnlyTextView = ViewUtils.getView(rootView, R.id.ttv__participants__header);
        headerEditText = ViewUtils.getView(rootView, R.id.taet__participants__header__editable);
        bottomBorder = ViewUtils.getView(rootView, R.id.v_participants__header__bottom_border);
        shieldView = ViewUtils.getView(rootView, R.id.sv__otr__verified_shield);
        shieldView.setVisibility(View.INVISIBLE);
        penIcon = ViewUtils.getView(rootView, R.id.gtv__participants_header__pen_icon);
        showPenIcon(false);

        closeButton.setAlpha(0);
        closeButton.setOnClickListener(this);

        headerEditText.setOnTouchListener(headerOnTouchListener);
        headerEditText.setOnEditorActionListener(editorActionListener);

        // Hide bottom border initially
        bottomBorder.setVisibility(View.GONE);

        // Toggle color background
        rootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getContainer().onClickedEmptyBackground();
            }
        });

        penIconHandler = new Handler();

        if (LayoutSpec.isTablet(getActivity())) {
            headerTopBorder.setVisibility(View.GONE);
        }

        return rootView;
    }

    @Override
    public void onStart() {
        super.onStart();
        if (userRequester == IConnectStore.UserRequester.POPOVER) {
            getStoreFactory().getConnectStore().addConnectRequestObserver(this);
            final User user = getStoreFactory().getSingleParticipantStore().getUser();
            getStoreFactory().getConnectStore().loadUser(user.getId(), userRequester);
        } else {
            getStoreFactory().getParticipantsStore().addParticipantsStoreObserver(this);
        }
        getControllerFactory().getConversationScreenController().addConversationControllerObservers(this);
        getControllerFactory().getAccentColorController().addAccentColorObserver(this);

        if (getControllerFactory().getConversationScreenController().isShowingParticipant()) {
            showCancelButton(true, false);
        }

        if (!getControllerFactory().getThemeController().isDarkTheme()) {
            headerEditText.setAccentColor(getControllerFactory().getAccentColorController().getColor());
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        headerEditText.clearFocus();
        getControllerFactory().getGlobalLayoutController().addKeyboardVisibilityObserver(this);
    }

    @Override
    public void onPause() {
        getControllerFactory().getGlobalLayoutController().removeKeyboardVisibilityObserver(this);
        KeyboardUtils.hideKeyboard(getActivity());
        super.onPause();
    }

    @Override
    public void onStop() {
        getControllerFactory().getAccentColorController().removeAccentColorObserver(this);
        getStoreFactory().getConnectStore().removeConnectRequestObserver(this);
        getControllerFactory().getConversationScreenController().removeConversationControllerObservers(this);
        getStoreFactory().getParticipantsStore().removeParticipantsStoreObserver(this);
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        headerTopBorder = null;
        subHeader = null;
        textViewAddressBookNameContainer = null;
        closeButton = null;
        headerReadOnlyTextView = null;
        headerEditText = null;
        bottomBorder = null;
        penIconHandler.removeCallbacks(null);
        penIconHandler = null;
        penIcon = null;
        shieldView = null;
        super.onDestroyView();
    }

    @Override
    public void onClick(View v) {
        if (userRequester == IConnectStore.UserRequester.POPOVER) {
            getContainer().dismissDialog();
        } else {
            getControllerFactory().getConversationScreenController().hideParticipants(true, false);
        }
    }

    @Override
    public void conversationUpdated(IConversation conversation) {
        if (conversation == null) {
            return;
        }
        isGroupConversation = conversation.getType() == IConversation.Type.GROUP;
        if (isGroupConversation) {
            subHeader.setAllCaps(false);
            textViewAddressBookNameContainer.setVisibility(View.GONE);
            headerReadOnlyTextView.setText(conversation.getName());
            if (conversation.isMemberOfConversation()) {
                headerEditText.setText(conversation.getName());
                headerEditText.setVisibility(View.VISIBLE);
            } else {
                headerEditText.setVisibility(View.GONE);
            }

            shieldView.setVisibility(View.GONE);
            penIcon.setVisibility(View.VISIBLE);
            headerReadOnlyTextView.setGravity(Gravity.LEFT);
            ViewUtils.setMarginLeft(headerReadOnlyTextView,
                    getResources().getDimensionPixelSize(R.dimen.participants__header__input_field__layout_margin));
            subHeader.setGravity(Gravity.LEFT);
            ViewUtils.setMarginRight(subHeader, getResources().getDimensionPixelSize(R.dimen.wire__padding__big));
            ViewUtils.setMarginLeft(subHeader, getResources().getDimensionPixelSize(R.dimen.wire__padding__big));

        } else {
            subHeader.setTextColor(getControllerFactory().getAccentColorController().getColor());
            subHeader.setAllCaps(true);
            // In 1:1 conversation, show full user name as conversation name in participant view
            headerEditText.setVisibility(View.GONE);
            penIcon.setVisibility(View.GONE);
            headerReadOnlyTextView.setGravity(Gravity.CENTER);
            ViewUtils.setMarginLeft(headerReadOnlyTextView, 0);
            subHeader.setGravity(Gravity.CENTER);
            ViewUtils.setMarginRight(subHeader, 0);
            ViewUtils.setMarginLeft(subHeader, 0);
            shieldView.setVisibility(
                    conversation.getOtherParticipant().getVerified() == Verification.VERIFIED ? View.VISIBLE
                            : View.INVISIBLE);
        }
    }

    @Override
    public void participantsUpdated(UsersList participants) {
        subHeader.setText(getResources().getQuantityString(R.plurals.participants__sub_header_xx_people,
                participants.size(), participants.size()));
        subHeader.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                getResources().getDimension(R.dimen.wire__text_size__small));
        subHeader.setOnClickListener(null);

        // Hide header bottom border
        bottomBorder.setVisibility(View.GONE);

        new Handler().post(new Runnable() {
            @Override
            public void run() {
                if (getView() != null && getContainer() != null) {
                    final int height = getView().getMeasuredHeight();
                    getControllerFactory().getConversationScreenController().setParticipantHeaderHeight(height);
                }
            }
        });
    }

    @Override
    public void otherUserUpdated(final User otherUser) {
        headerReadOnlyTextView.setText(otherUser.getName());

        // TODO: https://wearezeta.atlassian.net/browse/AN-4278
        //        textViewAddressBookNameContainer.setVisibility(View.VISIBLE);
        //        textViewAddressBookName.setText("Marc Prengemann");

        subHeader.setText(otherUser.getEmail());
        subHeader.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                getResources().getDimension(R.dimen.participants__subheader__font_size__one_to_one));
        subHeader.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final Uri uri = Uri.parse(String.format("mailto:%s", otherUser.getEmail()));
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                startActivity(intent);
            }
        });

        shieldView.setVisibility(otherUser.getVerified() == Verification.VERIFIED ? View.VISIBLE : View.INVISIBLE);

        new Handler().post(new Runnable() {
            @Override
            public void run() {
                if (getView() != null && getControllerFactory().getConversationScreenController() != null) {
                    final int height = getView().getMeasuredHeight();
                    getControllerFactory().getConversationScreenController().setParticipantHeaderHeight(height);
                }
            }
        });
    }

    public void showCancelButton(boolean show, boolean animate) {
        if (closeButton == null || headerTopBorder == null) {
            return;
        }

        if (show) {
            if (!animate) {
                closeButton.setAlpha(1);
            } else {
                headerTopBorder.animate().alpha(0)
                        .setDuration(
                                getResources().getInteger(R.integer.open_close_button__alpha__animation_duration))
                        .setStartDelay(getResources().getInteger(R.integer.open_close_button__alpha__delay))
                        .start();
                ObjectAnimator animator = ObjectAnimator.ofFloat(closeButton, View.ALPHA, 1);
                animator.setDuration(
                        getResources().getInteger(R.integer.open_close_button__alpha__animation_duration))
                        .setStartDelay(getResources().getInteger(R.integer.open_close_button__alpha__delay));
                animator.start();
            }
        } else {
            if (!animate) {
                closeButton.setAlpha(0);
            } else {
                ObjectAnimator animator = ObjectAnimator.ofFloat(closeButton, View.ALPHA, 0);
                animator.setDuration(
                        getResources().getInteger(R.integer.close_close_button__alpha__animation_duration))
                        .setStartDelay(getResources().getInteger(R.integer.close_close_button__alpha__delay));
                animator.start();

                headerTopBorder.animate().alpha(1)
                        .setDuration(
                                getResources().getInteger(R.integer.close_close_button__alpha__animation_duration))
                        .setStartDelay(getResources().getInteger(R.integer.close_close_button__alpha__delay))
                        .start();
            }
        }
    }

    private View.OnTouchListener headerOnTouchListener = new View.OnTouchListener() {
        private boolean downAction = false;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP && downAction) {
                if (MathUtils.floatEqual(headerEditText.getAlpha(), 0f)) {
                    // only if not already visible and network is available
                    getStoreFactory().getNetworkStore().doIfHasInternetOrNotifyUser(new NetworkAction() {
                        @Override
                        public void execute(NetworkMode networkMode) {
                            showEditHeader(true);
                        }

                        @Override
                        public void onNoNetwork() {
                            showOfflineRenameError();
                        }
                    });

                }
                downAction = false;
            } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
                downAction = true;
            }

            // consume touch event if there is no network.
            return !getStoreFactory().getNetworkStore().hasInternetConnection();

        }
    };

    private void showOfflineRenameError() {
        ViewUtils.showAlertDialog(getActivity(), R.string.alert_dialog__no_network__header,
                R.string.rename_conversation__no_network__message, R.string.alert_dialog__confirmation, null, true);
    }

    private TextView.OnEditorActionListener editorActionListener = new TextView.OnEditorActionListener() {

        @Override
        public boolean onEditorAction(final TextView textView, int actionId, KeyEvent event) {
            if (actionId == EditorInfo.IME_ACTION_DONE
                    || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {

                if (LayoutSpec.isPhone(getActivity())) {
                    renameConversation();
                }

                closeHeaderEditing();

                return true;

            }
            return false;
        }

        private void closeHeaderEditing() {
            headerEditText.clearFocus();
            final int height = getView().getMeasuredHeight();
            new Handler().post(new Runnable() {
                @Override
                public void run() {
                    getControllerFactory().getConversationScreenController().setParticipantHeaderHeight(height);
                }
            });
            InputMethodManager imm = (InputMethodManager) getActivity()
                    .getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(headerEditText.getWindowToken(), 0);
        }

    };

    private void resetName() {
        headerReadOnlyTextView.setText(getStoreFactory().getConversationStore().getCurrentConversation().getName());
    }

    private void renameConversation() {
        getStoreFactory().getNetworkStore().doIfHasInternetOrNotifyUser(new NetworkAction() {
            @Override
            public void execute(NetworkMode networkMode) {
                updateConversationName();
            }

            @Override
            public void onNoNetwork() {
                resetName();
                showOfflineRenameError();
            }
        });
    }

    private void updateConversationName() {
        if (headerEditText == null) {
            return;
        }

        String text = headerEditText.getText().toString();
        if (text.equals(getStoreFactory().getConversationStore().getCurrentConversation().getName())) {
            return;
        }
        if (!TextUtils.isEmpty(text.trim())) {
            getStoreFactory().getConversationStore().getCurrentConversation().setConversationName(text);
            headerReadOnlyTextView.setText(text);
            getControllerFactory().getTrackingController()
                    .updateSessionAggregates(RangedAttribute.CONVERSATION_RENAMES);
        }
    }

    private void showEditHeader(boolean edit) {
        getContainer().editingHeader(edit);
        if (edit) {
            headerEditText.setText(headerReadOnlyTextView.getText());
            headerEditText.setAlpha(1);
            headerEditText.requestFocus();
            getControllerFactory().getFocusController().setFocus(IFocusController.CONVERSATION_EDIT_NAME);
            headerEditText.setSelection(headerEditText.getText().length());
            KeyboardUtils.showKeyboard(getActivity());
            headerReadOnlyTextView.setAlpha(0);
            subHeader.setAlpha(0);
            closeButton.setAlpha(0);
            closeButton.setEnabled(false);
            showPenIcon(false);
        } else {
            headerEditText.setAlpha(0);
            headerEditText.requestLayout();
            headerReadOnlyTextView.setAlpha(1);
            headerEditText.clearFocus();
            subHeader.setAlpha(1);
            closeButton.setAlpha(1);
            closeButton.setEnabled(true);

            if (LayoutSpec.isTablet(getActivity())) {
                renameConversation();
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////////
    //
    //  Conversation Manager Notifications
    //
    //////////////////////////////////////////////////////////////////////////////////////////

    @Override
    public void onShowParticipants(View anchorView, boolean isSingleConversation, boolean isMemberOfConversation,
            boolean showDeviceTabIfSingle) {
        showCancelButton(true, true);
        if (!isSingleConversation && isMemberOfConversation) {
            startPenIconTimeOut();
        } else {
            if (penIcon != null) {
                showPenIcon(false);
            }
        }
    }

    @Override
    public void onHideParticipants(boolean orButtonPressed, boolean hideByConversationChange,
            boolean backOrButtonPressed) {

        if (LayoutSpec.isTablet(getActivity()) && !hideByConversationChange) {
            renameConversation();
        }

        showCancelButton(false, true);
    }

    @Override
    public void onShowEditConversationName(boolean edit) {
        showEditHeader(edit);
    }

    @Override
    public void setListOffset(int offset) {

    }

    @Override
    public void onHeaderViewMeasured(int participantHeaderHeight) {

    }

    @Override
    public void onScrollParticipantsList(int verticalOffset, boolean scrolledToBottom) {
        if (bottomBorder == null) {
            return;
        }
        if (verticalOffset > 0) {
            bottomBorder.setVisibility(View.VISIBLE);
        } else {
            bottomBorder.setVisibility(View.GONE);
        }
    }

    @Override
    public void onConversationLoaded() {

    }

    @Override
    public void onShowUser(User user) {

    }

    @Override
    public void onHideUser() {

    }

    @Override
    public void onShowCommonUser(User user) {

    }

    @Override
    public void onHideCommonUser() {

    }

    @Override
    public void onAddPeopleToConversation() {

    }

    @Override
    public void onShowConversationMenu(@IConversationScreenController.ConversationMenuRequester int requester,
            IConversation conversation, View anchorView) {

    }

    @Override
    public void onShowOtrClient(OtrClient otrClient, User user) {

    }

    @Override
    public void onShowCurrentOtrClient() {

    }

    @Override
    public void onHideOtrClient() {

    }

    @Override
    public void onShowLikesList(Message message) {

    }

    @Override
    public void onKeyboardVisibilityChanged(boolean keyboardIsVisible, int keyboardHeight, View currentFocus) {
        if (!keyboardIsVisible) {
            showEditHeader(false);
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////////
    //
    //  BackgroundImageObserver
    //
    //////////////////////////////////////////////////////////////////////////////////////////

    private void startPenIconTimeOut() {
        if (penIcon == null) {
            return;
        }
        showPenIcon(true);
        penIconHandler.removeCallbacks(penIconRunnable);
        penIconHandler.postDelayed(penIconRunnable,
                getResources().getInteger(R.integer.profile__pen_icon__hide_time_out));
    }

    private void showPenIcon(boolean show) {
        if (show) {
            penIcon.setVisibility(View.VISIBLE);
        } else {
            penIcon.setVisibility(View.GONE);
        }
    }

    @Override
    public void onMessagesUpdated(MessagesList messagesList) {

    }

    @Override
    public void onConnectUserUpdated(final User user, IConnectStore.UserRequester usertype) {
        if (usertype != userRequester) {
            return;
        }
        headerReadOnlyTextView.setText(user.getName());

        // TODO: https://wearezeta.atlassian.net/browse/AN-4278
        //        textViewAddressBookNameContainer.setVisibility(View.VISIBLE);
        //        textViewAddressBookName.setText("Marc Prengemann");

        subHeader.setText(user.getEmail());
        subHeader.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                getResources().getDimension(R.dimen.participants__subheader__font_size__one_to_one));
        if (!TextUtils.isEmpty(user.getEmail())) {
            subHeader.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    final Uri uri = Uri.parse(String.format("mailto:%s", user.getEmail()));
                    Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                    startActivity(intent);
                }
            });
        } else {
            subHeader.setOnClickListener(null);
        }
        headerEditText.setVisibility(View.GONE);

        new Handler().post(new Runnable() {
            @Override
            public void run() {
                if (getView() != null && getControllerFactory().getConversationScreenController() != null) {
                    final int height = getView().getMeasuredHeight();
                    getControllerFactory().getConversationScreenController().setParticipantHeaderHeight(height);
                }
            }
        });
    }

    @Override
    public void onCommonConnectionsUpdated(CommonConnections commonConnections) {

    }

    @Override
    public void onInviteRequestSent(IConversation conversation) {

    }

    @Override
    public void onAccentColorHasChanged(Object sender, int color) {
        if (isGroupConversation) {
            return;
        }
        subHeader.setTextColor(color);
        if (!getControllerFactory().getThemeController().isDarkTheme()) {
            headerEditText.setAccentColor(color);
        }
    }

    public interface Container {

        void editingHeader(boolean editing);

        void onClickedEmptyBackground();

        void dismissDialog();
    }
}