From 507bd110594159cc69ff73a84a6bbcdb39acd8e2 Mon Sep 17 00:00:00 2001 From: dylan-muszel <42148418+dylan-muszel@users.noreply.github.com> Date: Thu, 9 Jan 2020 15:00:33 -0300 Subject: [PATCH] Wolmo Bottom sheet dialog! (#66) * Adding wolmo bottom sheet dialog fragment * Injection * Adding on attached * Changing names --- core/build.gradle | 2 + .../WolmoBottomSheetDialogFragment.kt | 215 ++++++++++++++++++ .../WolmoBottomSheetDialogFragmentTest.java | 126 ++++++++++ 3 files changed, 343 insertions(+) create mode 100644 core/src/main/java/ar/com/wolox/wolmo/core/fragment/WolmoBottomSheetDialogFragment.kt create mode 100644 core/src/test/java/ar/com/wolox/wolmo/core/fragment/WolmoBottomSheetDialogFragmentTest.java diff --git a/core/build.gradle b/core/build.gradle index 8931283..8d083dd 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -53,6 +53,7 @@ buildscript { ext.assertj_version = '3.9.0' ext.android_ktx_version = '1.1.0' ext.coroutines_version = '1.3.3' + ext.androidx_material_version = '1.2.0-alpha03' } dependencies { @@ -63,6 +64,7 @@ dependencies { // Support api "androidx.appcompat:appcompat:$androidx_appcompat_version" + api "com.google.android.material:material:$androidx_material_version" // Testing as api to let tests package use it api "junit:junit:$junit_version" diff --git a/core/src/main/java/ar/com/wolox/wolmo/core/fragment/WolmoBottomSheetDialogFragment.kt b/core/src/main/java/ar/com/wolox/wolmo/core/fragment/WolmoBottomSheetDialogFragment.kt new file mode 100644 index 0000000..93ca027 --- /dev/null +++ b/core/src/main/java/ar/com/wolox/wolmo/core/fragment/WolmoBottomSheetDialogFragment.kt @@ -0,0 +1,215 @@ +/* + * Copyright (c) Wolox S.A + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package ar.com.wolox.wolmo.core.fragment + +import android.app.Dialog +import android.content.Context +import android.content.DialogInterface +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.view.KeyEvent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.Window +import android.view.WindowManager +import androidx.annotation.CallSuper +import androidx.fragment.app.FragmentManager +import ar.com.wolox.wolmo.core.permission.PermissionManager +import ar.com.wolox.wolmo.core.presenter.BasePresenter +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import dagger.android.support.AndroidSupportInjection +import dagger.android.support.DaggerAppCompatDialogFragment +import javax.inject.Inject + +/** + * Base implementation for [IWolmoFragment] for bottom sheet dialog fragments. This is in charge of + * inflating the view returned by [layout]. + * The presenter is created on [onCreate] if [handleArguments] returns true. + */ +abstract class WolmoBottomSheetDialogFragment

> : BottomSheetDialogFragment(), + IWolmoFragment { + + @Inject + lateinit var permissionManager: PermissionManager + + @Inject + lateinit var fragmentHandler: WolmoFragmentHandler

+ + /** Invoked when thee dialog is attached. */ + var onAttached: (() -> Unit)? = null + + val presenter: P + get() = fragmentHandler.presenter + + @CallSuper + override fun onAttach(context: Context) { + AndroidSupportInjection.inject(this) + onAttached?.invoke() + super.onAttach(context) + } + + override fun onCreateDialog(savedInstanceState: Bundle?) = super.onCreateDialog(savedInstanceState).apply { + window?.run { + requestFeature(Window.FEATURE_NO_TITLE) + clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + } + } + + override fun onStart() { + super.onStart() + dialog?.window?.run { + setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + setBackgroundDrawable(backgroundDrawable) + setOnBackPressedListener() + } + } + + /** + * Returns a [Drawable] for use as background in the window. + * If you want to disable the background drawable return null. + * By default this method returns the color #01FFFFFF + */ + open val backgroundDrawable: Drawable + get() = ColorDrawable(Color.argb(1, 255, 255, 255)) + + /** + * Sets a custom [android.content.DialogInterface.OnKeyListener] for the + * [Dialog] returned by [.getDialog] that calls [.onBackPressed] + * if the key pressed is the back key. + * + * Beware that, when clicking a key, the [android.content.DialogInterface.OnKeyListener] + * is called before delegating the event to other structures. For example, the back is handled + * here before sending it to an [Activity]. + */ + open fun setOnBackPressedListener() { + dialog?.setOnKeyListener { _: DialogInterface?, keyCode: Int, _: KeyEvent? -> + keyCode == KeyEvent.KEYCODE_BACK && onBackPressed() + } + } + + @CallSuper + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + fragmentHandler.onCreate(this) + } + + @CallSuper + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + return fragmentHandler.onCreateView(inflater, container) + } + + @CallSuper + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + fragmentHandler.onViewCreated(view) + } + + @CallSuper + override fun setMenuVisibility(visible: Boolean) { + super.setMenuVisibility(visible) + fragmentHandler.setMenuVisibility(visible) + } + + @CallSuper + override fun onResume() { + super.onResume() + fragmentHandler.onResume() + } + + @CallSuper + override fun onPause() { + super.onPause() + fragmentHandler.onPause() + } + + @CallSuper + override fun onDestroyView() { + fragmentHandler.onDestroyView() + super.onDestroyView() + } + + /** + * Reads arguments sent as a Bundle extras. + * + * @param arguments The bundle obtainable by the getExtras method of the intent. + * + * @return true if arguments were read successfully, false otherwise. + * Default implementation returns true. + */ + override fun handleArguments(arguments: Bundle?) = true + + /** + * Associates variables to views inflated from the XML resource + * provided in [IWolmoFragment.layout] + * Override if needed. + */ + override fun setUi(view: View?) {} + + /** + * Sets the listeners for the views of the fragment. + * Override if needed. + */ + override fun setListeners() {} + + /** + * Callback called when the fragment becomes visible to the user. + * Override if needed. + */ + override fun onVisible() {} + + /** + * Callback called when the fragment becomes hidden to the user. + * Override if needed. + */ + override fun onHide() {} + + /** + * Populates the view elements of the fragment. + * Override if needed. + */ + override fun populate() {} + + /** + * Shows the [BottomSheetDialogFragment] using the fragment. + * + * @param manager Fragment Manager to show the dialog fragment + */ + fun show(manager: FragmentManager) { + super.show(manager, javaClass.name) + } + + /** + * @see IWolmoFragment.onBackPressed + */ + override fun onBackPressed(): Boolean { + return false + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, + grantResults: IntArray) { + permissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults) + } +} \ No newline at end of file diff --git a/core/src/test/java/ar/com/wolox/wolmo/core/fragment/WolmoBottomSheetDialogFragmentTest.java b/core/src/test/java/ar/com/wolox/wolmo/core/fragment/WolmoBottomSheetDialogFragmentTest.java new file mode 100644 index 0000000..497ced1 --- /dev/null +++ b/core/src/test/java/ar/com/wolox/wolmo/core/fragment/WolmoBottomSheetDialogFragmentTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) Wolox S.A + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package ar.com.wolox.wolmo.core.fragment; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.junit.Before; +import org.junit.Test; + +import ar.com.wolox.wolmo.core.permission.PermissionManager; +import ar.com.wolox.wolmo.core.presenter.BasePresenter; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class WolmoBottomSheetDialogFragmentTest { + + private WolmoFragmentHandler> mWolmoFragmentHandlerMock; + private PermissionManager mPermissionManagerMock; + private WolmoBottomSheetDialogFragment mWolmoBottomSheetDialogFragmentSpy; + + @Before + @SuppressWarnings("unchecked") + public void beforeTest() { + mWolmoFragmentHandlerMock = mock(WolmoFragmentHandler.class); + mPermissionManagerMock = mock(PermissionManager.class); + + mWolmoBottomSheetDialogFragmentSpy = spy(WolmoBottomSheetDialogFragment.class); + mWolmoBottomSheetDialogFragmentSpy.fragmentHandler = mWolmoFragmentHandlerMock; + mWolmoBottomSheetDialogFragmentSpy.permissionManager = mPermissionManagerMock; + } + + @Test + public void onCreateViewShouldDelegateCall() { + LayoutInflater inflaterMock = mock(LayoutInflater.class); + ViewGroup viewGroupMock = mock(ViewGroup.class); + + mWolmoBottomSheetDialogFragmentSpy.onCreateView(inflaterMock, viewGroupMock, null); + verify(mWolmoFragmentHandlerMock, times(1)).onCreateView(eq(inflaterMock), eq(viewGroupMock)); + } + + @Test + public void onViewCreatedShouldDelegateCall() { + View viewMock = mock(View.class); + + mWolmoBottomSheetDialogFragmentSpy.onViewCreated(viewMock, null); + verify(mWolmoFragmentHandlerMock, times(1)).onViewCreated(viewMock); + } + + @Test + public void setMenuVisibilityShouldDelegateCall() { + mWolmoBottomSheetDialogFragmentSpy.setMenuVisibility(true); + verify(mWolmoFragmentHandlerMock, times(1)).setMenuVisibility(eq(true)); + } + + @Test + public void onResumeShouldDelegateCall() { + mWolmoBottomSheetDialogFragmentSpy.onResume(); + verify(mWolmoFragmentHandlerMock, times(1)).onResume(); + } + + @Test + public void onPauseShouldDelegateCall() { + mWolmoBottomSheetDialogFragmentSpy.onPause(); + verify(mWolmoFragmentHandlerMock, times(1)).onPause(); + } + + @Test + public void onDestroyViewShouldDelegateCall() { + mWolmoBottomSheetDialogFragmentSpy.onDestroyView(); + verify(mWolmoFragmentHandlerMock, times(1)).onDestroyView(); + } + + @Test + public void onRequestPermissionResultShouldDelegateCall() { + String[] permissions = new String[] { "perms" }; + int[] grantResults = new int[] { 123456 }; + + mWolmoBottomSheetDialogFragmentSpy.onRequestPermissionsResult(123, permissions, grantResults); + verify(mPermissionManagerMock, times(1)).onRequestPermissionsResult(eq(123), eq(permissions), eq(grantResults)); + } + + @Test + public void requirePresenterShouldDelegateCall() { + when(mWolmoFragmentHandlerMock.getPresenter()).thenReturn(new BasePresenter<>()); + + mWolmoBottomSheetDialogFragmentSpy.getPresenter(); + verify(mWolmoFragmentHandlerMock, times(1)).getPresenter(); + } + + public static class TestDialog extends WolmoDialogFragment { + + @Override + public int layout() { + return 12345; + } + + @Override + public void init() {} + } +}