/** * 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.newreg.fragments; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.PorterDuff; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v7.app.AlertDialog; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import com.waz.api.BitmapCallback; import com.waz.api.ImageAsset; import com.waz.api.LoadHandle; import com.waz.zclient.BaseActivity; import com.waz.zclient.OnBackPressedListener; import com.waz.zclient.R; import com.waz.zclient.controllers.accentcolor.AccentColorObserver; import com.waz.zclient.controllers.camera.CameraActionObserver; import com.waz.zclient.core.controllers.tracking.attributes.OutcomeAttribute; import com.waz.zclient.core.controllers.tracking.attributes.RegistrationEventContext; import com.waz.zclient.core.controllers.tracking.events.registration.AddedPhotoEvent; import com.waz.zclient.pages.BaseFragment; import com.waz.zclient.pages.main.conversation.AssetIntentsManager; import com.waz.zclient.pages.main.profile.camera.CameraContext; import com.waz.zclient.pages.main.profile.camera.CameraFragment; import com.waz.zclient.tracking.GlobalTrackingController; import com.waz.zclient.ui.utils.BitmapUtils; import com.waz.zclient.ui.utils.ColorUtils; import com.waz.zclient.ui.utils.KeyboardUtils; import com.waz.zclient.ui.utils.ResourceUtils; import com.waz.zclient.ui.views.ZetaButton; import com.waz.zclient.utils.ViewUtils; import com.waz.zclient.views.ProgressView; public class SignUpPhotoFragment extends BaseFragment<SignUpPhotoFragment.Container> implements CameraFragment.Container, CameraActionObserver, AccentColorObserver, OnBackPressedListener { public static final String TAG = SignUpPhotoFragment.class.getName(); public static final String UNSPLASH_API_URL = "https://source.unsplash.com/800x800/?landscape"; public static final String UNSPLASH_API_URL_LOW_RES = "https://source.unsplash.com/256x256/?landscape"; private static final String SAVED_INSTANCE_CAMERA_REVEALED = "SAVED_INSTANCE_CAMERA_REVEALED"; private static final String SAVED_INSTANCE_DIALOG = "SAVED_INSTANCE_DIALOG"; private static final String SAVED_INSTANCE_IMAGE_LOADED = "SAVED_INSTANCE_IMAGE_LOADED"; private static final String ARGUMENT_REGISTRATION_TYPE = "ARGUMENT_REGISTRATION_TYPE"; private FrameLayout initContainer; private boolean cameraRevealed; private RegistrationType registrationType; private ImageView initImage; private ZetaButton chooseOwnButton; private ZetaButton keepButton; private AlertDialog sourceSelectionDialog; private LinearLayout progressContainer; private ProgressView progressView; private LoadHandle unsplashImageLoadHandle; private boolean isImageLoaded; public enum RegistrationType { Phone, Email } public static SignUpPhotoFragment newInstance(RegistrationType registrationType) { SignUpPhotoFragment newFragment = new SignUpPhotoFragment(); Bundle args = new Bundle(); args.putSerializable(ARGUMENT_REGISTRATION_TYPE, registrationType); newFragment.setArguments(args); return newFragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_sign_up_photo, container, false); initContainer = ViewUtils.getView(view, R.id.fl__photo_container); progressContainer = ViewUtils.getView(view, R.id.ll__init_photo__loading_container); progressView = ViewUtils.getView(view, R.id.pv__init_photo__loading); progressContainer.setVisibility(View.VISIBLE); initImage = ViewUtils.getView(view, R.id.iv__init_photo); final ImageView vignetteOverlay = ViewUtils.getView(view, R.id.iv_background_vignette_overlay); vignetteOverlay.setImageBitmap(BitmapUtils.getVignetteBitmap(getResources())); chooseOwnButton = ViewUtils.getView(view, R.id.zb__choose_own_picture); chooseOwnButton.setIsFilled(true); chooseOwnButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showChooseSourceDialog(); } }); keepButton = ViewUtils.getView(view, R.id.zb__keep_picture); keepButton.setIsFilled(false); keepButton.setEnabled(false); keepButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { handleSelectedBitmap(getContainer().getUnsplashImageAsset(), AddedPhotoEvent.PhotoSource.UNSPLASH); } }); if (savedInstanceState == null) { registrationType = (RegistrationType) getArguments().getSerializable(ARGUMENT_REGISTRATION_TYPE); } else { registrationType = (RegistrationType) savedInstanceState.getSerializable(ARGUMENT_REGISTRATION_TYPE); cameraRevealed = savedInstanceState.getBoolean(SAVED_INSTANCE_CAMERA_REVEALED); isImageLoaded = savedInstanceState.getBoolean(SAVED_INSTANCE_IMAGE_LOADED); if (savedInstanceState.getBoolean(SAVED_INSTANCE_DIALOG)) { showChooseSourceDialog(); } if (cameraRevealed) { initContainer.setVisibility(View.GONE); initImage.setVisibility(View.GONE); } } final int darkenColor = ColorUtils.injectAlpha(ResourceUtils.getResourceFloat(getResources(), R.dimen.background_solid_black_overlay_opacity), Color.BLACK); initImage.setColorFilter(darkenColor, PorterDuff.Mode.DARKEN); vignetteOverlay.setColorFilter(darkenColor, PorterDuff.Mode.DARKEN); if (!isImageLoaded) { initImage.setAlpha(0f); initImage.setVisibility(View.GONE); } final int displayWidth = ViewUtils.getOrientationDependentDisplayWidth(getActivity()); if (unsplashImageLoadHandle != null) { unsplashImageLoadHandle.cancel(); unsplashImageLoadHandle = null; } unsplashImageLoadHandle = getContainer().getUnsplashImageAsset().getSingleBitmap(displayWidth, new BitmapCallback() { @Override public void onBitmapLoaded(final Bitmap bitmap) { if (keepButton == null || progressContainer == null || initImage == null) { return; } keepButton.setEnabled(true); initImage.setImageBitmap(bitmap); if (!isImageLoaded) { ViewUtils.fadeInView(initImage); progressContainer.animate() .alpha(0) .withEndAction(new Runnable() { @Override public void run() { progressContainer.setVisibility(View.GONE); progressView.stopAnimation(); } }) .start(); } else { initContainer.setVisibility(View.VISIBLE); progressContainer.setVisibility(View.GONE); progressView.stopAnimation(); } isImageLoaded = true; } @Override public void onBitmapLoadingFailed(BitmapLoadingFailed reason) { if (progressContainer == null) { return; } progressContainer.animate() .alpha(0) .withEndAction(new Runnable() { @Override public void run() { progressContainer.setVisibility(View.GONE); progressView.stopAnimation(); } }) .start(); } }); return view; } private void showChooseSourceDialog() { if (sourceSelectionDialog != null && sourceSelectionDialog.isShowing()) { return; } sourceSelectionDialog = new AlertDialog.Builder(getActivity()) .setTitle(R.string.sign_up__take_picture_dialog__title) .setMessage(R.string.sign_up__take_picture_dialog__message) .setPositiveButton(R.string.sign_up__take_picture_dialog__camera, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ViewUtils.fadeOutView(initContainer); ViewUtils.fadeOutView(initImage); cameraRevealed = true; launchCameraFragment(false); dialog.dismiss(); } }) .setNegativeButton(R.string.sign_up__take_picture_dialog__gallery, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ViewUtils.fadeOutView(initContainer); ViewUtils.fadeOutView(initImage); cameraRevealed = true; launchCameraFragment(true); dialog.dismiss(); } }) .setNeutralButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }) .setCancelable(true) .create(); sourceSelectionDialog.show(); } @Override public void onStart() { super.onStart(); getControllerFactory().getAccentColorController().addAccentColorObserver(this); getControllerFactory().getCameraController().addCameraActionObserver(this); getControllerFactory().getVerificationController().finishVerification(); if (KeyboardUtils.keyboardIsVisible(getView())) { KeyboardUtils.hideKeyboard(getActivity()); } if (cameraRevealed && !isCameraFragmentAlreadyStarted()) { launchCameraFragment(false); initContainer.setVisibility(View.GONE); initImage.setVisibility(View.GONE); } } @Override public void onAccentColorHasChanged(Object sender, int color) { chooseOwnButton.setAccentColor(color); keepButton.setAccentColor(color); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { //noinspection deprecation keepButton.setTextColor(getResources().getColor(R.color.text__primary_dark)); } else { keepButton.setTextColor(getResources().getColor(R.color.text__primary_dark, getContext().getTheme())); } } @Override public void onStop() { getControllerFactory().getCameraController().removeCameraActionObserver(this); getControllerFactory().getAccentColorController().removeAccentColorObserver(this); super.onStop(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Fragment fragment = getChildFragmentManager().findFragmentByTag(CameraFragment.TAG); if (fragment != null) { if (requestCode == AssetIntentsManager.IntentType.GALLERY.requestCode && resultCode == Activity.RESULT_OK) { initContainer.setVisibility(View.GONE); initImage.setVisibility(View.GONE); } fragment.onActivityResult(requestCode, resultCode, data); } } @Override public boolean onBackPressed() { Fragment fragment = getChildFragmentManager().findFragmentByTag(CameraFragment.TAG); if (fragment != null) { dismissCameraFragment(); return true; } else { if (getActivity() == null || getStoreFactory() == null || getStoreFactory().isTornDown()) { return false; } getStoreFactory().getAppEntryStore().onBackPressed(); return true; } } @Override public void onDestroyView() { if (unsplashImageLoadHandle != null) { unsplashImageLoadHandle.cancel(); unsplashImageLoadHandle = null; } super.onDestroyView(); } private void dismissCameraFragment() { Fragment fragment = getChildFragmentManager().findFragmentByTag(CameraFragment.TAG); if (fragment != null) { getChildFragmentManager().popBackStack(CameraFragment.TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); ViewUtils.fadeInView(initContainer); ViewUtils.fadeInView(initImage); cameraRevealed = false; } } private void launchCameraFragment(boolean showGallery) { getChildFragmentManager().beginTransaction() .add(R.id.fl__sign_up__camera_container, CameraFragment.newInstance(CameraContext.SIGN_UP, showGallery), CameraFragment.TAG) .addToBackStack(CameraFragment.TAG) .commit(); } private boolean isCameraFragmentAlreadyStarted() { return getChildFragmentManager().findFragmentByTag(CameraFragment.TAG) != null; } public void onSaveInstanceState(Bundle outState) { outState.putBoolean(SAVED_INSTANCE_CAMERA_REVEALED, cameraRevealed); outState.putBoolean(SAVED_INSTANCE_DIALOG, sourceSelectionDialog != null && sourceSelectionDialog.isShowing()); outState.putBoolean(SAVED_INSTANCE_IMAGE_LOADED, isImageLoaded); super.onSaveInstanceState(outState); } ////////////////////////////////////////////////////////////////////////////////////////// // // Picture taking // ////////////////////////////////////////////////////////////////////////////////////////// @Override public void onBitmapSelected(final ImageAsset imageAsset, boolean imageFromCamera, CameraContext cameraContext) { if (cameraContext != CameraContext.SIGN_UP) { return; } dismissCameraFragment(); AddedPhotoEvent.PhotoSource photoSource = imageFromCamera ? AddedPhotoEvent.PhotoSource.CAMERA : AddedPhotoEvent.PhotoSource.GALLERY; handleSelectedBitmap(imageAsset, photoSource); } @Override public void onCameraNotAvailable() { } @Override public void onOpenCamera(CameraContext cameraContext) { } @Override public void onCloseCamera(CameraContext cameraContext) { getActivity().onBackPressed(); } private void handleSelectedBitmap(final ImageAsset imageAsset, final AddedPhotoEvent.PhotoSource photoSource) { new Handler().postDelayed(new Runnable() { @Override public void run() { if (registrationType == RegistrationType.Phone) { getStoreFactory().getAppEntryStore().setPhonePicture(imageAsset); } else { getStoreFactory().getAppEntryStore().setEmailPicture(imageAsset); } RegistrationEventContext registrationEventContext = registrationType == SignUpPhotoFragment.RegistrationType.Phone ? getStoreFactory().getAppEntryStore().getPhoneRegistrationContext() : getStoreFactory().getAppEntryStore().getEmailRegistrationContext(); ((BaseActivity) getActivity()).injectJava(GlobalTrackingController.class).tagEvent(new AddedPhotoEvent(OutcomeAttribute.SUCCESS, "", photoSource, registrationEventContext)); } }, getResources().getInteger(R.integer.signup__photo__selected_photo_display_delay)); } public interface Container { ImageAsset getUnsplashImageAsset(); } }