├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── art ├── screenshot1.gif └── screenshot2.gif ├── library ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── tuenti │ │ └── buttonmenu │ │ ├── ButtonMenu.java │ │ ├── animator │ │ ├── ObjectAnimatorFactory.java │ │ └── ScrollAnimator.java │ │ └── viewmodel │ │ ├── button │ │ ├── ButtonCommand.java │ │ ├── ButtonVM.java │ │ ├── ButtonVMListener.java │ │ ├── ButtonWithCounterVM.java │ │ ├── ButtonWithMutableSubjectAndResourceVM.java │ │ ├── ButtonWithMutableSubjectVM.java │ │ ├── ButtonWithProgressVM.java │ │ ├── CounterButtonVM.java │ │ ├── MutableResourceButtonVM.java │ │ ├── MutableSubjectButtonVM.java │ │ ├── NullButtonVMListener.java │ │ ├── ProgressButtonVM.java │ │ └── SimpleButtonVM.java │ │ └── buttonmenu │ │ ├── ButtonMenuVM.java │ │ ├── OnButtonCommandExecuted.java │ │ └── SimpleButtonMenuVM.java │ └── test │ └── java │ └── com │ └── tuenti │ └── buttonmenu │ ├── ButtonMenuTest.java │ ├── animator │ └── ScrollAnimatorTest.java │ └── viewmodel │ ├── button │ ├── ButtonVMTest.java │ ├── ButtonWithCounterVMTest.java │ ├── ButtonWithMutableSubjectAndResourceVMTest.java │ ├── ButtonWithMutableSubjectVMTest.java │ ├── ButtonWithProgressVMTest.java │ └── SimpleButtonVMTest.java │ └── buttonmenu │ └── SimpleButtonMenuVMTest.java ├── pom.xml └── sample ├── AndroidManifest.xml ├── pom.xml ├── res ├── drawable-hdpi │ ├── app_icon.png │ ├── contact_icon.png │ ├── moment_icon.png │ ├── photo_icon.png │ └── refresh_icon.png ├── drawable-mdpi │ ├── app_icon.png │ ├── contact_icon.png │ ├── moment_icon.png │ ├── photo_icon.png │ └── refresh_icon.png ├── drawable-xhdpi │ ├── app_icon.png │ ├── contact_icon.png │ ├── moment_icon.png │ ├── photo_icon.png │ └── refresh_icon.png ├── drawable │ └── button_menu.xml ├── layout │ ├── activity_main.xml │ ├── activity_second.xml │ ├── contact_button.xml │ ├── contact_row.xml │ ├── moment_button.xml │ ├── photo_button.xml │ ├── photo_with_subtitle_button.xml │ └── progress_button.xml └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml └── src └── main └── java └── com └── tuenti └── buttonmenu └── sample └── ui ├── Agenda.java ├── Contact.java ├── activity ├── MainActivity.java └── SecondActivity.java ├── buttonmenu ├── CustomButtonMenuVM.java ├── SecondButtonMenuVM.java └── command │ └── ShowToastCommand.java └── renderer ├── ContactRenderer.java └── ContactRendererBuilder.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Copyright: Tuenti Technologies 2 | 3 | # built application files 4 | *.apk 5 | *.ap_ 6 | *.jar 7 | 8 | # lint folder 9 | lint 10 | 11 | # files for the dex VM 12 | *.dex 13 | 14 | # Java class files 15 | *.class 16 | 17 | # generated files 18 | bin/ 19 | gen/ 20 | classes/ 21 | gen-external-apklibs/ 22 | 23 | # maven output folder 24 | target 25 | 26 | # Local configuration file (sdk path, etc) 27 | local.properties 28 | 29 | # Eclipse project files 30 | .classpath 31 | .project 32 | .metadata 33 | .settings 34 | 35 | # IntelliJ files 36 | .idea 37 | *.iml 38 | 39 | # OSX files 40 | .DS_Store 41 | 42 | # Windows files 43 | Thumbs.db 44 | 45 | # vi swap files 46 | *.swp 47 | 48 | # backup files 49 | *.bak 50 | 51 | # gradle directory 52 | .gradle 53 | gradlew 54 | gradlew.bat 55 | gradle/ 56 | build/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | android: 4 | components: 5 | - build-tools-18.1.1 6 | - android-18 7 | - extra-android-support 8 | - extra-google-m2repository 9 | - extra-android-m2repository 10 | 11 | before_install: 12 | - cp -R $ANDROID_HOME/extras/android/m2repository/ ~/.m2/repository/ 13 | 14 | install: mvn clean install 15 | 16 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Button Menu [![Build Status](https://travis-ci.org/tuenti/ButtonMenu.svg?branch=master)](https://travis-ci.org/tuenti/ButtonMenu) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.tuenti.buttonmenu/library/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.tuenti.buttonmenu/library) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Button%20Menu-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/887) 2 | =========== 3 | 4 | ButtonMenu is an Android library created to build user interfaces based on buttons. This library has been implemented 5 | using Model View ViewModel pattern combined with an Android custom view that extends LinearLayout. 6 | 7 | In this library you will find a custom view implementation called ButtonMenu and a custom animator called 8 | ScrollAnimator you can use to link the scroll of a ListView with your ButtonMenu to show or hide the view when the 9 | user uses the ListView scroll. 10 | 11 | This library works on Android 2.X or higher versions. 12 | 13 | Screenshots 14 | ----------- 15 | 16 | ![Demo Screenshot 1][1] 17 | ![Demo Screenshot 2][2] 18 | 19 | Download 20 | -------- 21 | 22 | Download the project, compile it using ``mvn clean install`` import ``buttonmenu-1.0.9.jar`` into your project. 23 | 24 | Or declare it into your pom.xml 25 | 26 | ```xml 27 | 28 | com.tuenti.buttonmenu 29 | library 30 | 1.0.9 31 | 32 | ``` 33 | 34 | 35 | Or into your build.gradle 36 | ```groovy 37 | dependencies{ 38 | compile 'com.tuenti.buttonmenu:library:1.0.9' 39 | } 40 | ``` 41 | 42 | 43 | Usage 44 | ----- 45 | 46 | * 1. Add a ``ButtonMenu`` to your layout. 47 | 48 | ```xml 49 | 52 | ``` 53 | 54 | * 2. Initialize your ButtonMenu widget with a ButtonMenuVM implementation inside your Activity or Fragment. You can use 55 | our SimpleButtonMenuVM implementation or create your own ButtonMenuVM implementation. 56 | 57 | ```java 58 | private void initializeButtonMenu() { 59 | button_menu = (ButtonMenu) findViewById(R.id.button_menu); 60 | button_menu.setButtonMenuVM(buttonMenuVM); 61 | button_menu.initialize(); 62 | } 63 | ``` 64 | 65 | * 3. If you want to create your custom ButtonMenuVM implementation you can follow the sample implemented in 66 | CustomButtonMenuVM. 67 | 68 | ```java 69 | public class CustomButtonMenuVM extends SimpleButtonMenuVM { 70 | 71 | /* 72 | * Every ButtonVM implementation could be moved to a different file extending SimpleButtonVM if needed. 73 | */ 74 | private final ButtonVM moment = new SimpleButtonVM(R.layout.moment_button, R.id.moment, null); 75 | private final ButtonVM photo = new SimpleButtonVM(R.layout.photo_button, R.id.photo, null); 76 | private final ButtonVM contact = new SimpleButtonVM(R.layout.contact_button, R.id.contact, null); 77 | 78 | public CustomButtonMenuVM() { 79 | super(); 80 | addItem(moment); 81 | addItem(photo); 82 | addItem(contact); 83 | } 84 | ``` 85 | 86 | * 4. Connect your ButtonMenu widget with the ScrollAnimator to attach the scroll animation effect. 87 | 88 | ```java 89 | private void initializeScrollAnimator() { 90 | ScrollAnimator scrollAnimator = new ScrollAnimator(button_menu, new ObjectAnimatorFactory()); 91 | scrollAnimator.configureListView(lv_contacts); 92 | scrollAnimator.setDurationInMillis(300); 93 | } 94 | ``` 95 | 96 | Review different ButtonVM implementations -like ``SimpleButtonVM`` or ``ButtonWithMutableSubjectVM`` - in this 97 | project if you want to create your custom ButtonVM. 98 | 99 | Credits & Contact 100 | ----------------- 101 | 102 | ButtonMenu was created by [Android team at Tuenti Technologies S.L.](http://github.com/tuenti). You can follow Tuenti 103 | engineering team on Twitter [@tuentieng](http://twitter.com/tuentieng). 104 | 105 | License 106 | ------- 107 | 108 | ButtonMenu is available under the Apache License, Version 2.0. See LICENSE.txt file for more info. 109 | 110 | [1]: ./art/screenshot1.gif 111 | [2]: ./art/screenshot2.gif 112 | -------------------------------------------------------------------------------- /art/screenshot1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/art/screenshot1.gif -------------------------------------------------------------------------------- /art/screenshot2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/art/screenshot2.gif -------------------------------------------------------------------------------- /library/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | com.tuenti.buttonmenu 7 | buttonmenu-parent 8 | 1.0.10-SNAPSHOT 9 | 10 | 11 | library 12 | jar 13 | 14 | ButtonMenu - Library 15 | 16 | 17 | 18 | 19 | junit 20 | junit 21 | 22 | 23 | 24 | org.robolectric 25 | robolectric 26 | 27 | 28 | 29 | org.mockito 30 | mockito-all 31 | 32 | 33 | 34 | com.nineoldandroids 35 | library 36 | 37 | 38 | 39 | 40 | 41 | 42 | ${project.basedir}/src/test/java 43 | 44 | 45 | com.jayway.maven.plugins.android.generation2 46 | android-maven-plugin 47 | true 48 | 49 | false 50 | 51 | false 52 | 53 | ${project.basedir}/res 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/ButtonMenu.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu; 18 | 19 | import android.annotation.TargetApi; 20 | import android.content.Context; 21 | import android.os.Build.VERSION_CODES; 22 | import android.util.AttributeSet; 23 | import android.view.LayoutInflater; 24 | import android.view.View; 25 | import android.view.ViewGroup; 26 | import android.widget.Button; 27 | import android.widget.LinearLayout; 28 | import android.widget.TextView; 29 | 30 | import com.tuenti.buttonmenu.viewmodel.button.ButtonCommand; 31 | import com.tuenti.buttonmenu.viewmodel.button.ButtonVM; 32 | import com.tuenti.buttonmenu.viewmodel.button.ButtonVMListener; 33 | import com.tuenti.buttonmenu.viewmodel.button.ButtonWithProgressVM; 34 | import com.tuenti.buttonmenu.viewmodel.button.CounterButtonVM; 35 | import com.tuenti.buttonmenu.viewmodel.button.MutableResourceButtonVM; 36 | import com.tuenti.buttonmenu.viewmodel.button.MutableSubjectButtonVM; 37 | import com.tuenti.buttonmenu.viewmodel.buttonmenu.ButtonMenuVM; 38 | import com.tuenti.buttonmenu.viewmodel.buttonmenu.ButtonMenuVM.ButtonMenuVMListener; 39 | import com.tuenti.buttonmenu.viewmodel.buttonmenu.OnButtonCommandExecuted; 40 | 41 | import java.util.Collection; 42 | import java.util.HashMap; 43 | import java.util.Map; 44 | import java.util.Map.Entry; 45 | import java.util.Set; 46 | 47 | /** 48 | * Base custom view created extending LinearLayout. This class works as the core of ButtonMenu library. 49 | *

50 | * Add a ButtonMenuVM implementation to this component to show a list of buttons. 51 | * 52 | * @author "Pedro Vicente Gómez Sánchez" 53 | */ 54 | public class ButtonMenu extends LinearLayout implements ButtonVMListener, ButtonMenuVMListener { 55 | 56 | private static final int MIN_WEIGHT_SUM = 0; 57 | static final float WEIGHT_SUM = 100.0f; 58 | 59 | private Map items; 60 | private ButtonMenuVM buttonMenuVM; 61 | private OnButtonCommandExecuted onButtonCommandExecutedListener; 62 | 63 | public ButtonMenu(Context context) { 64 | super(context); 65 | initializeView(); 66 | } 67 | 68 | public ButtonMenu(Context context, AttributeSet attrs) { 69 | super(context, attrs); 70 | initializeView(); 71 | } 72 | 73 | @TargetApi(VERSION_CODES.HONEYCOMB) 74 | public ButtonMenu(Context context, AttributeSet attrs, int defStyle) { 75 | super(context, attrs, defStyle); 76 | initializeView(); 77 | } 78 | 79 | /** 80 | * Join the Activity/Fragment lifecycle to the ButtonMenu custom view lifecycle. Call this method from the 81 | * initialize of your Activity/Fragment. 82 | */ 83 | public void initialize() { 84 | clean(); 85 | renderButtonMenuVM(); 86 | registerListeners(); 87 | } 88 | 89 | /** 90 | * Join the Activity/Fragment lifecycle to the ButtonMenu custom view lifecycle. Call this method from the 91 | * release of your Activity/Fragment. 92 | */ 93 | public void release() { 94 | unregisterListeners(); 95 | clean(); 96 | } 97 | 98 | /** 99 | * Set the view model to configure the button menu state. 100 | * This method should be called before initialize method. 101 | * 102 | * @param buttonMenuVM used to configure the custom view 103 | */ 104 | public void setButtonMenuVM(ButtonMenuVM buttonMenuVM) { 105 | this.buttonMenuVM = buttonMenuVM; 106 | } 107 | 108 | /** 109 | * Obtain the ButtonMenuVM implementation associated to the ButtonMenu instance. 110 | */ 111 | public ButtonMenuVM getButtonMenuVM() { 112 | return buttonMenuVM; 113 | } 114 | 115 | /** 116 | * Attach a OnActionCommandExecutedListener to the ButtonMenu. 117 | * 118 | * @param onButtonCommandExecutedListener - The OnActionCommandExecutedListener to be attached. 119 | */ 120 | public void setOnButtonCommandExecutedListener(OnButtonCommandExecuted onButtonCommandExecutedListener) { 121 | this.onButtonCommandExecutedListener = onButtonCommandExecutedListener; 122 | } 123 | 124 | @Override 125 | public void onEnablePropertyChanged(boolean enabled, ButtonVM buttonVM) { 126 | View view = getViewForViewModel(buttonVM); 127 | setIsEnabled(buttonVM, view, enabled); 128 | } 129 | 130 | @Override 131 | public void onCounterValueChanged(int counterValue, CounterButtonVM buttonVM) { 132 | View view = getViewForViewModel(buttonVM); 133 | int counterResourceId = buttonVM.getCounterWidgetId(); 134 | renderCounter(buttonVM, view, counterResourceId); 135 | } 136 | 137 | @Override 138 | public void onImageResourceChanged(int imageResourceId, MutableResourceButtonVM buttonVM) { 139 | View view = getViewForViewModel(buttonVM); 140 | int viewResourceToChange = buttonVM.getResIdToChangeResource(); 141 | renderImageResource(view, viewResourceToChange, imageResourceId); 142 | } 143 | 144 | @Override 145 | public void onSubjectChanged(String subject, MutableSubjectButtonVM buttonVM) { 146 | View view = getViewForViewModel(buttonVM); 147 | int subjectResourceId = buttonVM.getResIdToInsertSubject(); 148 | renderSubject(view, subject, subjectResourceId); 149 | } 150 | 151 | @Override 152 | public void onButtonVMAdded(final ButtonVM buttonVM) { 153 | add(buttonVM); 154 | addItem(buttonVM); 155 | } 156 | 157 | @Override 158 | public void onButtonVMRemoved(final ButtonVM buttonVM) { 159 | remove(buttonVM); 160 | removeItem(buttonVM); 161 | } 162 | 163 | @Override 164 | public void onProgressValueChanged(boolean loading, ButtonWithProgressVM buttonVM) { 165 | View view = getViewForViewModel(buttonVM); 166 | int imageId = buttonVM.getImage(); 167 | int progressId = buttonVM.getProgress(); 168 | renderProgress(view, imageId, progressId, loading); 169 | } 170 | 171 | 172 | private void renderButtonMenuVM() { 173 | if (buttonMenuVM != null && buttonMenuVM.getButtonVMs() != null) { 174 | Set buttonVMList = this.buttonMenuVM.getButtonVMs(); 175 | for (ButtonVM buttonVM : buttonVMList) { 176 | addItem(buttonVM); 177 | } 178 | } 179 | } 180 | 181 | private void addItem(final ButtonVM buttonVM) { 182 | if (!items.containsKey(buttonVM)) { 183 | View view = renderItem(buttonVM); 184 | hookActions(view, buttonVM); 185 | items.put(buttonVM, view); 186 | updateWeight(); 187 | } 188 | } 189 | 190 | private void removeItem(final ButtonVM buttonVM) { 191 | if (items.containsKey(buttonVM)) { 192 | items.remove(buttonVM); 193 | updateWeight(); 194 | } 195 | } 196 | 197 | private void initializeView() { 198 | initItemsCollection(); 199 | initWeightSum(); 200 | } 201 | 202 | private void initItemsCollection() { 203 | items = new HashMap(); 204 | } 205 | 206 | private LayoutInflater getLayoutInflater() { 207 | Context context = this.getContext(); 208 | return LayoutInflater.from(context); 209 | } 210 | 211 | private void initWeightSum() { 212 | // If the weight is unset or is not valid, we set it. 213 | if (getWeightSum() <= MIN_WEIGHT_SUM) { 214 | setWeightSum(WEIGHT_SUM); 215 | } 216 | } 217 | 218 | private View renderItem(ButtonVM buttonVM) { 219 | LayoutInflater layoutInflater = getLayoutInflater(); 220 | View view = layoutInflater.inflate(buttonVM.getLayoutId(), null); 221 | this.addView(view); 222 | if (!buttonVM.isEnabled()) { 223 | setIsEnabled(buttonVM, view, false); 224 | } 225 | return view; 226 | } 227 | 228 | private void hookActions(final View view, final ButtonVM buttonVM) { 229 | boolean isEnabled = buttonVM.isEnabled(); 230 | view.setEnabled(isEnabled); 231 | View clickableView = view.findViewById(buttonVM.getClickableResId()); 232 | if (clickableView != null) { 233 | clickableView.setOnClickListener(new OnClickListener() { 234 | @Override 235 | public void onClick(View view) { 236 | ButtonCommand actionCommand = buttonVM.getButtonCommand(); 237 | if (actionCommand != null) { 238 | notifyActionCommandListener(); 239 | actionCommand.execute(); 240 | } 241 | } 242 | }); 243 | } 244 | } 245 | 246 | private void notifyActionCommandListener() { 247 | if (onButtonCommandExecutedListener != null) { 248 | onButtonCommandExecutedListener.onActionCommandExecuted(); 249 | } 250 | } 251 | 252 | private void updateWeight() { 253 | Collection views = items.values(); 254 | int viewCount = views.size(); 255 | float weight = getWeightSum() / viewCount; 256 | for (View view : views) { 257 | LinearLayout.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, 258 | ViewGroup.LayoutParams.MATCH_PARENT, weight); 259 | view.setLayoutParams(layoutParams); 260 | } 261 | 262 | } 263 | 264 | private void unregisterListeners() { 265 | unregisterButtonMenuVMListener(); 266 | unregisterButtonVMListener(); 267 | } 268 | 269 | private void registerListeners() { 270 | registerButtonMenuVMListener(); 271 | registerButtonVMListener(); 272 | } 273 | 274 | private void registerButtonVMListener() { 275 | for (ButtonVM buttonVM : items.keySet()) { 276 | buttonVM.registerListener(this); 277 | } 278 | } 279 | 280 | private void unregisterButtonVMListener() { 281 | for (ButtonVM buttonVM : items.keySet()) { 282 | buttonVM.unregisterListener(); 283 | } 284 | } 285 | 286 | private void registerButtonMenuVMListener() { 287 | if (buttonMenuVM != null) { 288 | buttonMenuVM.registerListener(this); 289 | } 290 | } 291 | 292 | private void unregisterButtonMenuVMListener() { 293 | buttonMenuVM.unregisterListener(this); 294 | } 295 | 296 | private void setIsEnabled(final ButtonVM buttonVM, final View view, final boolean enabled) { 297 | int[] viewsIdToChange = buttonVM.getViewIdsToEnableOrDisable(); 298 | for (int viewIdToChange : viewsIdToChange) { 299 | View viewToChange = view.findViewById(viewIdToChange); 300 | if (viewToChange != null) { 301 | viewToChange.setEnabled(enabled); 302 | } 303 | } 304 | view.setEnabled(enabled); 305 | } 306 | 307 | @TargetApi(VERSION_CODES.CUPCAKE) 308 | private void renderImageResource(View view, int viewResourceToChange, int imageResourceId) { 309 | Button button = (Button) view.findViewById(viewResourceToChange); 310 | if (button != null) { 311 | button.setCompoundDrawablesWithIntrinsicBounds(0, imageResourceId, 0, 0); 312 | } 313 | } 314 | 315 | private void renderSubject(View view, String subject, int subjectResourceId) { 316 | Button button = (Button) view.findViewById(subjectResourceId); 317 | if (button != null) { 318 | button.setText(subject); 319 | } 320 | } 321 | 322 | private void renderCounter(CounterButtonVM viewModel, View view, int counterResourceId) { 323 | TextView counter = (TextView) view.findViewById(counterResourceId); 324 | int counterValue = viewModel.getCounterValue(); 325 | if (counterValue <= 0) { 326 | counter.setVisibility(View.INVISIBLE); 327 | } else { 328 | counter.setVisibility(View.VISIBLE); 329 | } 330 | String newCounter = "" + counterValue; 331 | counter.setText(newCounter); 332 | } 333 | 334 | private void renderProgress(View view, int viewResourceId, int progressResourceId, 335 | boolean show) { 336 | View image = view.findViewById(viewResourceId); 337 | View progressBar = view.findViewById(progressResourceId); 338 | image.setVisibility(show ? View.GONE : View.VISIBLE); 339 | progressBar.setVisibility(show ? View.VISIBLE : View.GONE); 340 | } 341 | 342 | private View getViewForViewModel(final ButtonVM viewModel) { 343 | View view = null; 344 | Set> entries = items.entrySet(); 345 | for (Entry entry : entries) { 346 | if (entry.getKey().equals(viewModel)) { 347 | view = entry.getValue(); 348 | break; 349 | } 350 | } 351 | return view; 352 | } 353 | 354 | private void clean() { 355 | for (View view : items.values()) { 356 | this.removeView(view); 357 | } 358 | items = new HashMap(); 359 | } 360 | 361 | private void add(final ButtonVM buttonVM) { 362 | View view = getViewForViewModel(buttonVM); 363 | if (view != null) { 364 | addView(view); 365 | } 366 | } 367 | 368 | private void remove(final ButtonVM buttonVM) { 369 | View view = getViewForViewModel(buttonVM); 370 | if (view != null) { 371 | removeView(view); 372 | } 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/animator/ObjectAnimatorFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.animator; 18 | 19 | import android.view.View; 20 | 21 | import com.nineoldandroids.animation.ObjectAnimator; 22 | 23 | /** 24 | * ObjectAnimator factory created to provide ObjectAnimator objects used in ScrollAnimator to perform push in / push 25 | * out animations. 26 | * 27 | * @author Pedro Vicente Gómez Sánchez 28 | */ 29 | public class ObjectAnimatorFactory { 30 | 31 | public ObjectAnimator getObjectAnimator(View animatedView, String animationType, int translationY) { 32 | return ObjectAnimator.ofFloat(animatedView, animationType, translationY); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/animator/ScrollAnimator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.animator; 18 | 19 | 20 | import android.view.View; 21 | import android.widget.AbsListView; 22 | import android.widget.AbsListView.OnScrollListener; 23 | import android.widget.ListView; 24 | 25 | import com.nineoldandroids.animation.Animator; 26 | import com.nineoldandroids.animation.ObjectAnimator; 27 | 28 | 29 | /** 30 | * Animate a view with a "translationY" animation when the user scrolls a ListView. This class registers 31 | * a scroll listener when a ListView is associated using "configureListView" method. 32 | * 33 | * @author Pedro Vicente Gómez Sánchez 34 | */ 35 | public class ScrollAnimator { 36 | 37 | private static final int SCROLL_DIRECTION_CHANGE_THRESHOLD = 5; 38 | private static final String ANIMATION_TYPE = "translationY"; 39 | private static final int DEFAULT_ANIMATION_DURATION_IN_MILLISECONDS = 200; 40 | private static final int HIDDEN_Y_POSITION = 0; 41 | protected static final int SCROLL_TO_TOP = -1; 42 | protected static final int SCROLL_TO_BOTTOM = 1; 43 | 44 | private final View animatedView; 45 | private final ObjectAnimatorFactory objectAnimatorFactory; 46 | private ListView listView; 47 | private OnScrollListener additionalScrollListener; 48 | private int scrollDirection = 0; 49 | private long durationInMillis = DEFAULT_ANIMATION_DURATION_IN_MILLISECONDS; 50 | 51 | public ScrollAnimator(View animatedView, ObjectAnimatorFactory objectAnimatorFactory) { 52 | this.animatedView = animatedView; 53 | this.objectAnimatorFactory = objectAnimatorFactory; 54 | } 55 | 56 | /** 57 | * Configure an additional scroll listener to be notified when the ListView scroll is updated. 58 | * 59 | * @param additionalScrollListener to notify. 60 | */ 61 | public void setAdditionalScrollListener(OnScrollListener additionalScrollListener) { 62 | this.additionalScrollListener = additionalScrollListener; 63 | } 64 | 65 | /** 66 | * Associate a ListView to listen in order to perform the "translationY" animation when the ListView scroll is 67 | * updated. This method is going to set a "OnScrollListener" to the ListView passed as argument. 68 | * 69 | * @param listView to listen. 70 | */ 71 | public void configureListView(ListView listView) { 72 | this.listView = listView; 73 | this.listView.setOnScrollListener(new OnScrollListener() { 74 | 75 | int scrollPosition; 76 | 77 | @Override 78 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 79 | notifyScrollToAdditionalScrollListener(view, firstVisibleItem, visibleItemCount, totalItemCount); 80 | View topChild = view.getChildAt(0); 81 | 82 | int newScrollPosition; 83 | if (topChild == null) { 84 | newScrollPosition = 0; 85 | } else { 86 | newScrollPosition = view.getFirstVisiblePosition() * topChild.getHeight() - topChild.getTop(); 87 | } 88 | if (Math.abs(newScrollPosition - scrollPosition) >= SCROLL_DIRECTION_CHANGE_THRESHOLD) { 89 | onScrollPositionChanged(scrollPosition, newScrollPosition); 90 | } 91 | 92 | scrollPosition = newScrollPosition; 93 | } 94 | 95 | @Override 96 | public void onScrollStateChanged(AbsListView view, int scrollState) { 97 | notifyScrollStateChangedToAdditionalScrollListener(view, scrollState); 98 | 99 | } 100 | }); 101 | } 102 | 103 | /** 104 | * Configure the "translationY" animation duration. 105 | * 106 | * @param duration in milliseconds. 107 | */ 108 | public void setDurationInMillis(long duration) { 109 | this.durationInMillis = duration; 110 | } 111 | 112 | /** 113 | * Remove the scroll listener associated to the configured ListView. 114 | */ 115 | public void release() { 116 | listView.setOnScrollListener(null); 117 | } 118 | 119 | /** 120 | * Show the animated view using a "translationY" animation. 121 | */ 122 | public void showWithAnimation() { 123 | showWithAnimationWithListener(null); 124 | } 125 | 126 | /** 127 | * Show the animated view using a "translationY" animation and configure an AnimatorListener to be notified during 128 | * the animation. 129 | */ 130 | public void showWithAnimationWithListener(Animator.AnimatorListener animatorListener) { 131 | scrollDirection = SCROLL_TO_TOP; 132 | ObjectAnimator objectAnimator = objectAnimatorFactory.getObjectAnimator(animatedView, ANIMATION_TYPE, HIDDEN_Y_POSITION); 133 | if (animatorListener != null) { 134 | objectAnimator.addListener(animatorListener); 135 | } 136 | objectAnimator.setDuration(durationInMillis); 137 | objectAnimator.start(); 138 | } 139 | 140 | /** 141 | * Hide the animated view using a "translationY" animation. 142 | */ 143 | public void hideWithAnimation() { 144 | hideWithAnimationWithListener(null); 145 | } 146 | 147 | /** 148 | * Hide the animated view using a "translationY" animation and configure an AnimatorListener to be notified 149 | * during the animation. 150 | */ 151 | public void hideWithAnimationWithListener(Animator.AnimatorListener animatorListener) { 152 | scrollDirection = SCROLL_TO_BOTTOM; 153 | ObjectAnimator objectAnimator = objectAnimatorFactory.getObjectAnimator(animatedView, ANIMATION_TYPE, animatedView.getHeight()); 154 | if (animatorListener != null) { 155 | objectAnimator.addListener(animatorListener); 156 | } 157 | objectAnimator.setDuration(durationInMillis); 158 | objectAnimator.start(); 159 | } 160 | 161 | /** 162 | * Animate animated view from the current position to a "translationY" position. 163 | * 164 | * @param translationY final position. 165 | */ 166 | protected void animate(int translationY) { 167 | ObjectAnimator animator = objectAnimatorFactory.getObjectAnimator(animatedView, ANIMATION_TYPE, translationY); 168 | animator.setDuration(durationInMillis); 169 | animator.start(); 170 | } 171 | 172 | private void notifyScrollToAdditionalScrollListener(AbsListView view, int firstVisibleItem, int visibleItemCount, 173 | int totalItemCount) { 174 | if (additionalScrollListener != null) { 175 | additionalScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); 176 | } 177 | } 178 | 179 | private void notifyScrollStateChangedToAdditionalScrollListener(AbsListView view, int scrollState) { 180 | if (additionalScrollListener != null) { 181 | additionalScrollListener.onScrollStateChanged(view, scrollState); 182 | } 183 | } 184 | 185 | /** 186 | * Perform the "translateY" animation using the new scroll position and the old scroll position to show or hide 187 | * the animated view. 188 | * 189 | * @param oldScrollPosition 190 | * @param newScrollPosition 191 | */ 192 | private void onScrollPositionChanged(int oldScrollPosition, int newScrollPosition) { 193 | int newScrollDirection; 194 | 195 | if (newScrollPosition < oldScrollPosition) { 196 | newScrollDirection = SCROLL_TO_TOP; 197 | } else { 198 | newScrollDirection = SCROLL_TO_BOTTOM; 199 | } 200 | 201 | if (directionHasChanged(newScrollDirection)) { 202 | translateYAnimatedView(newScrollDirection); 203 | } 204 | } 205 | 206 | private boolean directionHasChanged(int newScrollDirection) { 207 | return newScrollDirection != scrollDirection; 208 | } 209 | 210 | private void translateYAnimatedView(int newScrollDirection) { 211 | scrollDirection = newScrollDirection; 212 | animatedView.post(new Runnable() { 213 | 214 | @Override 215 | public void run() { 216 | int translationY = hasScrolledToTop() ? HIDDEN_Y_POSITION : animatedView.getHeight(); 217 | animate(translationY); 218 | } 219 | }); 220 | } 221 | 222 | private boolean hasScrolledToTop() { 223 | return scrollDirection == SCROLL_TO_TOP; 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/ButtonCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * Command pattern implementation created to associate actions to ButtonVMs. 21 | * 22 | * @author Pedro Vicente Gómez Sánchez 23 | */ 24 | public interface ButtonCommand { 25 | 26 | public void execute(); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/ButtonVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | 20 | /** 21 | * Interface created to represent a ButtonVM. This interface have to be implemented by each item added to 22 | * ButtonMenuVM implementations. 23 | *

24 | * This view model contains information for each item in a ButtonMenu. Contains the presentation state for each item 25 | * and have to be used to modify the item. 26 | * 27 | * @author "Pedro Vicente Gómez Sánchez" 28 | */ 29 | public interface ButtonVM { 30 | 31 | /** 32 | * Method used to check if the item should be shown as enabled or disabled. 33 | * 34 | * @return true if enabled; otherwise false; 35 | */ 36 | boolean isEnabled(); 37 | 38 | /** 39 | * Disable the item and notify the ButtonVMListener. 40 | */ 41 | void disable(); 42 | 43 | /** 44 | * Enable the item and notify the ButtonVMListener. 45 | */ 46 | void enable(); 47 | 48 | /** 49 | * Method used by the ButtonMenu to inflate the view when a new item it's added to this component. 50 | * 51 | * @return an integer that represents the R.layout identifier. 52 | */ 53 | int getLayoutId(); 54 | 55 | /** 56 | * Method used by the ButtonMenu to execute a command with the onClickListener for one item has been executed. 57 | * This method can return a NULL ActionCommand if the implementation doesn't contains one. 58 | * 59 | * @return an ActionCommand implementation or null. 60 | */ 61 | ButtonCommand getButtonCommand(); 62 | 63 | /** 64 | * Register a listener to notify some changes like the enable or disable change. 65 | * 66 | * @param listener to register. 67 | */ 68 | void registerListener(ButtonVMListener listener); 69 | 70 | /** 71 | * Un-register a listener from the listener collection. 72 | */ 73 | void unregisterListener(); 74 | 75 | /** 76 | * Method used by the ButtonMenu to hook the View.OnClickListenerMethod. 77 | * 78 | * @return an integer that represents the R.id identifier. 79 | */ 80 | int getClickableResId(); 81 | 82 | /** 83 | * Method used by the ButtonMenu to retrieve information about which widgets must be enabled or disabled when the 84 | * client code execute a disable or enable methods. 85 | * 86 | * @return a integer array that represents the R.id identifier to be disabled or enabled. 87 | */ 88 | int[] getViewIdsToEnableOrDisable(); 89 | 90 | /** 91 | * Method used to update the action command stored in a ButtonMenu. 92 | * 93 | * @param actionCommand 94 | */ 95 | void setButtonCommand(ButtonCommand actionCommand); 96 | } 97 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/ButtonVMListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * Interface created to work as a listener for ButtonVM. This interface contains some methods called when the client 21 | * code interacts with a ButtonVM. 22 | * 23 | * @author "Pedro Vicente Gómez Sánchez" 24 | */ 25 | public interface ButtonVMListener { 26 | 27 | /** 28 | * Method executed when the enable() or disable() method it's executed in a ButtonVM. 29 | * 30 | * @param enabled boolean represents the new ButtonVM state. 31 | * @param buttonVM that has suffer the change. 32 | */ 33 | void onEnablePropertyChanged(final boolean enabled, final ButtonVM buttonVM); 34 | 35 | /** 36 | * Method executed when the counter value has changed in a CounterButtonVM. 37 | * 38 | * @param counterValue new counterValue change in the view model. 39 | * @param buttonVM that has suffer the change. 40 | */ 41 | void onCounterValueChanged(final int counterValue, final CounterButtonVM buttonVM); 42 | 43 | /** 44 | * Method executed when the image resource has changed in a ImageResourceChangeVM. 45 | * 46 | * @param imageResourceId new image identifier. 47 | * @param buttonVM that has suffer the change. 48 | */ 49 | void onImageResourceChanged(final int imageResourceId, final MutableResourceButtonVM buttonVM); 50 | 51 | /** 52 | * Method executed when the subject value change in the view model. 53 | * 54 | * @param subject new subject value. 55 | * @param buttonVm that has suffer the change. 56 | */ 57 | void onSubjectChanged(final String subject, final MutableSubjectButtonVM buttonVm); 58 | 59 | /** 60 | * Method executed when the progress value change in the view model. 61 | * 62 | * @param loading new state of progressbar loading 63 | * @param buttonVm that has suffer the change. 64 | */ 65 | void onProgressValueChanged(boolean loading, final ButtonWithProgressVM buttonVm); 66 | } 67 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/ButtonWithCounterVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * CounterButtonVM implementation based on SimpleButtonVM. This entity can be used by different components to 21 | * represent a simple button that can change the counter associated. 22 | * 23 | * @author "Pedro Vicente Gómez Sánchez" 24 | */ 25 | public class ButtonWithCounterVM extends SimpleButtonVM implements CounterButtonVM { 26 | 27 | private int counterValue; 28 | private final int counterWidgetId; 29 | 30 | public ButtonWithCounterVM(int layoutId, boolean enabled, int clickableResId, int[] enableDisableResIds, 31 | ButtonCommand actionCommand, 32 | int counterValue, int counterWidgetId) { 33 | super(layoutId, enabled, clickableResId, enableDisableResIds, actionCommand); 34 | this.counterValue = counterValue; 35 | this.counterWidgetId = counterWidgetId; 36 | } 37 | 38 | @Override 39 | public int getCounterValue() { 40 | return counterValue; 41 | } 42 | 43 | @Override 44 | public void setCounterValue(final int counterValue) { 45 | this.counterValue = counterValue; 46 | notifyCounterListener(counterValue); 47 | } 48 | 49 | @Override 50 | public int getCounterWidgetId() { 51 | return counterWidgetId; 52 | } 53 | 54 | private void notifyCounterListener(final int counterValue) { 55 | getListener().onCounterValueChanged(counterValue, this); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/ButtonWithMutableSubjectAndResourceVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | 20 | /** 21 | * ButtonVM implementation. This entity can be used by different components to represent a simple button that can 22 | * change this subject and image resource associated. The component that use this implementation must declare the 23 | * interface ButtonVM. 24 | * 25 | * @author "Pedro Vicente Gómez Sánchez" 26 | */ 27 | public class ButtonWithMutableSubjectAndResourceVM extends SimpleButtonVM implements MutableSubjectButtonVM, 28 | MutableResourceButtonVM { 29 | 30 | private int imageId; 31 | private int imageResourceId; 32 | private String subject; 33 | private int subjectResourceId; 34 | 35 | 36 | public ButtonWithMutableSubjectAndResourceVM(int layoutId, boolean enabled, 37 | int clickableResId, int[] 38 | enableDisableResIds, ButtonCommand actionCommand, int imageResourceId, 39 | int subjectResourceId) { 40 | super(layoutId, enabled, clickableResId, enableDisableResIds, actionCommand); 41 | this.imageResourceId = imageResourceId; 42 | this.subjectResourceId = subjectResourceId; 43 | } 44 | 45 | @Override 46 | public int getImageResourceId() { 47 | return imageId; 48 | } 49 | 50 | @Override 51 | public void setImageResourceId(final int imageId) { 52 | this.imageId = imageId; 53 | notifyImageResourceChanged(); 54 | } 55 | 56 | @Override 57 | public int getResIdToChangeResource() { 58 | return imageResourceId; 59 | } 60 | 61 | @Override 62 | public String getSubject() { 63 | return subject; 64 | } 65 | 66 | @Override 67 | public void setSubject(final String subject) { 68 | this.subject = subject; 69 | notifySubjectChanged(); 70 | } 71 | 72 | 73 | @Override 74 | public int getResIdToInsertSubject() { 75 | return subjectResourceId; 76 | } 77 | 78 | private void notifyImageResourceChanged() { 79 | ButtonVMListener buttonVMListener = getListener(); 80 | buttonVMListener.onImageResourceChanged(this.imageId, this); 81 | } 82 | 83 | private void notifySubjectChanged() { 84 | ButtonVMListener buttonVMListener = getListener(); 85 | buttonVMListener.onSubjectChanged(this.subject, this); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/ButtonWithMutableSubjectVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * ButtonWithMutableSubjectVM implementation based on SimpleButtonVM. This entity can be used by different components to 21 | * represent a simple button that can change the subject associated. 22 | * 23 | * @author "Pedro Vicente Gómez Sánchez" 24 | */ 25 | public class ButtonWithMutableSubjectVM extends SimpleButtonVM implements MutableSubjectButtonVM { 26 | 27 | private String subject; 28 | private int subjectResourceId; 29 | 30 | public ButtonWithMutableSubjectVM(int layoutId, int clickableResId, ButtonCommand actionCommand) { 31 | this(layoutId, true, clickableResId, new int[]{clickableResId}, clickableResId, actionCommand); 32 | } 33 | 34 | public ButtonWithMutableSubjectVM(int layoutId, boolean enabled, int clickableResId, 35 | int[] enableDisableResIds, int subjectResourceId, ButtonCommand actionCommand) { 36 | super(layoutId, enabled, clickableResId, enableDisableResIds, actionCommand); 37 | this.subjectResourceId = subjectResourceId; 38 | } 39 | 40 | @Override 41 | public String getSubject() { 42 | return subject; 43 | } 44 | 45 | @Override 46 | public void setSubject(final String subject) { 47 | this.subject = subject; 48 | notifySubjectChanged(); 49 | } 50 | 51 | @Override 52 | public int getResIdToInsertSubject() { 53 | return subjectResourceId; 54 | } 55 | 56 | private void notifySubjectChanged() { 57 | ButtonVMListener buttonVMListener = getListener(); 58 | buttonVMListener.onSubjectChanged(this.subject, this); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/ButtonWithProgressVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * ButtonWithProgressVM implementation based on SimpleButtonVM. This entity can be used by different components to 21 | * represent a simple button with a progressBar associated. 22 | * 23 | * @author "Iñaki Villar Algaba" 24 | */ 25 | public class ButtonWithProgressVM extends SimpleButtonVM implements ProgressButtonVM { 26 | 27 | private int imageViewId; 28 | private int progressViewId; 29 | private boolean loading; 30 | 31 | public ButtonWithProgressVM(int layoutId, boolean enabled, int clickableResId, 32 | int[] enableDisableResIds, ButtonCommand actionCommand, int imageViewId, 33 | int progressBarId) { 34 | super(layoutId, enabled, clickableResId, enableDisableResIds, actionCommand); 35 | this.imageViewId = imageViewId; 36 | this.progressViewId = progressBarId; 37 | this.loading = false; 38 | } 39 | 40 | @Override 41 | public void showLoading() { 42 | loading = true; 43 | notifyShowProgress(); 44 | } 45 | 46 | @Override 47 | public void closeLoading() { 48 | loading = false; 49 | notifyCloseProgress(); 50 | } 51 | 52 | @Override 53 | public int getProgress() { 54 | return progressViewId; 55 | } 56 | 57 | @Override 58 | public int getImage() { 59 | return imageViewId; 60 | } 61 | 62 | @Override 63 | public boolean isLoading() { 64 | return loading; 65 | } 66 | 67 | private void notifyShowProgress() { 68 | ButtonVMListener buttonVMListener = getListener(); 69 | buttonVMListener.onProgressValueChanged(true, this); 70 | } 71 | 72 | private void notifyCloseProgress() { 73 | ButtonVMListener buttonVMListener = getListener(); 74 | buttonVMListener.onProgressValueChanged(false, this); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/CounterButtonVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * Interface created to represent a ButtonVM that supports a counter. This interface have to be implemented by each 21 | * item added to ButtonMenuVM that use a counter inside the button. 22 | * 23 | * @author "Pedro Vicente Gómez Sánchez" 24 | */ 25 | public interface CounterButtonVM extends ButtonVM { 26 | 27 | /** 28 | * @return an integer with the counter value stored in this ButtonVM. 29 | */ 30 | int getCounterValue(); 31 | 32 | /** 33 | * Modify the counter value stored in this ButtonVM and notify the ButtonVMListener that the value has changed. 34 | * 35 | * @param counterValue with the new value. 36 | */ 37 | void setCounterValue(final int counterValue); 38 | 39 | /** 40 | * @return the identifier associated to the widget that works as counter. 41 | */ 42 | int getCounterWidgetId(); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/MutableResourceButtonVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * Interface created to represent a ButtonVM that supports a image that can change. This interface have to be 21 | * implemented by each item added to ButtonMenuVM that use a image that can change inside the button. 22 | * 23 | * @author "Pedro Vicente Gómez Sánchez" 24 | */ 25 | public interface MutableResourceButtonVM extends ButtonVM { 26 | 27 | /** 28 | * @return the resource id associated to the image. 29 | */ 30 | int getImageResourceId(); 31 | 32 | /** 33 | * Change the resource id associated to the image stored in the ButtonVM and notify the ButtonVMListener. 34 | * 35 | * @param imageId to store. 36 | */ 37 | public void setImageResourceId(final int imageId); 38 | 39 | /** 40 | * @return an integer with the widget identifier that it's going to change the source image using the image 41 | * resource identifier. 42 | */ 43 | public int getResIdToChangeResource(); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/MutableSubjectButtonVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * Interface created to represent a ButtonVM that supports a subject. This interface have to be implemented by each 21 | * item added to ButtonMenuVM that use a subject inside the button. 22 | * 23 | * @author "Pedro Vicente Gómez Sánchez" 24 | */ 25 | public interface MutableSubjectButtonVM extends ButtonVM { 26 | 27 | /** 28 | * @return the subject stored in the ButtonVM 29 | */ 30 | String getSubject(); 31 | 32 | /** 33 | * Change the subject stored in the view model and notify the ButtonVMListener the change. 34 | * 35 | * @param subject changed. 36 | */ 37 | void setSubject(final String subject); 38 | 39 | /** 40 | * @return an integer associated to the resource id that it's going to store the image change. 41 | */ 42 | int getResIdToInsertSubject(); 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/NullButtonVMListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * Null Object pattern implementation used to avoid null checks in ButtonVM. 21 | * 22 | * @author "Pedro Vicente Gómez Sánchez" 23 | */ 24 | class NullButtonVMListener implements ButtonVMListener { 25 | 26 | @Override 27 | public void onEnablePropertyChanged(boolean enabled, ButtonVM buttonVM) { 28 | //Empty 29 | } 30 | 31 | @Override 32 | public void onCounterValueChanged(int counterValue, CounterButtonVM buttonVM) { 33 | //Empty 34 | } 35 | 36 | @Override 37 | public void onImageResourceChanged(int imageResourceId, MutableResourceButtonVM buttonVM) { 38 | //Empty 39 | } 40 | 41 | @Override 42 | public void onSubjectChanged(String subject, MutableSubjectButtonVM buttonVm) { 43 | //Empty 44 | } 45 | 46 | @Override 47 | public void onProgressValueChanged(boolean view, ButtonWithProgressVM buttonVm) { 48 | //Empty 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/ProgressButtonVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * Interface created to represent a ButtonVM that supports a progressBar. This interface have to be 21 | * implemented by each item added to ButtonMenuVM that use a progressBar inside the button. 22 | * 23 | * @author "Iñaki Villar Algaba" 24 | */ 25 | public interface ProgressButtonVM extends ButtonVM { 26 | 27 | /** 28 | * Change the state starting loading in the view model and notify the ButtonVMListener the 29 | * change. 30 | */ 31 | void showLoading(); 32 | 33 | /** 34 | * Change the state finishing loading in the view model and notify the ButtonVMListener the 35 | * change 36 | */ 37 | void closeLoading(); 38 | 39 | /** 40 | * @return the resource id associated to the progress 41 | */ 42 | int getProgress(); 43 | 44 | /** 45 | * @return the resource id associated to the image. 46 | */ 47 | int getImage(); 48 | 49 | /** 50 | * @return the state of loading of ProgressBar. 51 | */ 52 | boolean isLoading(); 53 | } 54 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/button/SimpleButtonVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | /** 20 | * Base ButtonVM implementation. This entity can be used by different components to represent a simple button that can't 21 | * change and contains an button command associated. 22 | * 23 | * @author "Pedro Vicente Gómez Sánchez" 24 | */ 25 | public class SimpleButtonVM implements ButtonVM { 26 | 27 | private final int layoutId; 28 | private boolean enabled; 29 | private final int clickableResId; 30 | private final int[] enableDisableResIds; 31 | private ButtonCommand buttonCommand; 32 | private ButtonVMListener listener; 33 | 34 | public SimpleButtonVM() { 35 | this(0, 0, null); 36 | } 37 | 38 | public SimpleButtonVM(int layoutId, int clickableResId, ButtonCommand buttonCommand) { 39 | this(layoutId, true, clickableResId, new int[]{clickableResId}, buttonCommand); 40 | } 41 | 42 | public SimpleButtonVM(int layoutId, boolean enabled, int clickableResId, int[] enableDisableResIds, 43 | ButtonCommand buttonCommand) { 44 | this.layoutId = layoutId; 45 | this.enabled = enabled; 46 | this.clickableResId = clickableResId; 47 | this.enableDisableResIds = enableDisableResIds; 48 | this.buttonCommand = buttonCommand; 49 | this.listener = new NullButtonVMListener(); 50 | } 51 | 52 | @Override 53 | public boolean isEnabled() { 54 | return enabled; 55 | } 56 | 57 | @Override 58 | public void disable() { 59 | final boolean enabled = false; 60 | setEnabled(enabled); 61 | notifyIsEnabledListener(enabled); 62 | } 63 | 64 | @Override 65 | public void enable() { 66 | final boolean enabled = true; 67 | setEnabled(enabled); 68 | notifyIsEnabledListener(enabled); 69 | } 70 | 71 | @Override 72 | public int getLayoutId() { 73 | return layoutId; 74 | } 75 | 76 | @Override 77 | public ButtonCommand getButtonCommand() { 78 | return buttonCommand; 79 | } 80 | 81 | @Override 82 | public void registerListener(ButtonVMListener listener) { 83 | this.listener = listener; 84 | } 85 | 86 | @Override 87 | public void unregisterListener() { 88 | this.listener = new NullButtonVMListener(); 89 | } 90 | 91 | @Override 92 | public int getClickableResId() { 93 | return clickableResId; 94 | } 95 | 96 | @Override 97 | public int[] getViewIdsToEnableOrDisable() { 98 | return enableDisableResIds; 99 | } 100 | 101 | @Override 102 | public void setButtonCommand(ButtonCommand buttonCommand) { 103 | this.buttonCommand = buttonCommand; 104 | } 105 | 106 | protected ButtonVMListener getListener() { 107 | return listener; 108 | } 109 | 110 | private void setEnabled(boolean enabled) { 111 | this.enabled = enabled; 112 | } 113 | 114 | private void notifyIsEnabledListener(final boolean enabled) { 115 | this.listener.onEnablePropertyChanged(enabled, this); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/buttonmenu/ButtonMenuVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.buttonmenu; 18 | 19 | import java.util.Set; 20 | 21 | import com.tuenti.buttonmenu.viewmodel.button.ButtonVM; 22 | 23 | 24 | /** 25 | * Interface created to represent a ButtonMenu view model with some ButtonVM inside. 26 | * This view model supports the addition and removal of ButtonVM items. 27 | * 28 | * @author "Pedro Vicente Gómez Sánchez" 29 | */ 30 | public interface ButtonMenuVM { 31 | 32 | /** 33 | * @return a list of ButtonVM stored in this view model. 34 | */ 35 | Set getButtonVMs(); 36 | 37 | /** 38 | * Registers a ButtonMenuVMListener item that will be notified when a ButtonVM is 39 | * added to/removed from the ButtonMenuVM. 40 | * 41 | * @param ButtonMenuVMListener to register. 42 | */ 43 | void registerListener(ButtonMenuVMListener listener); 44 | 45 | /** 46 | * Un-registers a ButtonMenuVMListener. 47 | * 48 | * @param ButtonMenuVMListener to un-register. 49 | */ 50 | void unregisterListener(ButtonMenuVMListener listener); 51 | 52 | /** 53 | * Enable every ButtonVM in the ButtonMenuVM. 54 | */ 55 | void enable(); 56 | 57 | /** 58 | * Disable every ButtonVM in the ButtonMenuVM. 59 | */ 60 | void disable(); 61 | 62 | /** 63 | * Interface created to represent a listener for the addition/removal of ButtonVM items. 64 | */ 65 | interface ButtonMenuVMListener { 66 | 67 | /** 68 | * Notifies of a ButtonVM addition. 69 | * 70 | * @param buttonVM to notify it's addition. 71 | */ 72 | void onButtonVMAdded(ButtonVM buttonVM); 73 | 74 | /** 75 | * Notifies of a ButtonVM removal. 76 | * 77 | * @param buttonVM to notify it's removal. 78 | */ 79 | void onButtonVMRemoved(ButtonVM buttonVM); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/buttonmenu/OnButtonCommandExecuted.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.buttonmenu; 18 | 19 | /** 20 | * Listener created to be executed when a ButtonVm ActionCommand it's executed. 21 | * 22 | * @author "Pedro Vicente Gómez Sánchez" 23 | */ 24 | public interface OnButtonCommandExecuted { 25 | 26 | /** 27 | * Method executed when an action command it's executed. 28 | */ 29 | void onActionCommandExecuted(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/com/tuenti/buttonmenu/viewmodel/buttonmenu/SimpleButtonMenuVM.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.buttonmenu; 18 | 19 | import java.util.Collection; 20 | import java.util.LinkedHashSet; 21 | import java.util.LinkedList; 22 | import java.util.Set; 23 | 24 | import com.tuenti.buttonmenu.viewmodel.button.ButtonVM; 25 | 26 | /** 27 | * Main implementation of ButtonMenuVM. This entity contain the business logic associated to store ButtonVM's. 28 | * This class it's going to be extended by GroupConversationButtonMenuVm and IndividualConversationButtonMenuVm. This 29 | * entity has been created to avoid duplicate code. 30 | * 31 | * @author "Pedro Vicente Gómez Sánchez" 32 | */ 33 | public class SimpleButtonMenuVM implements ButtonMenuVM { 34 | 35 | private final Set buttonVMs; 36 | private ButtonMenuVMListener listener; 37 | 38 | public SimpleButtonMenuVM() { 39 | this(new LinkedList()); 40 | } 41 | 42 | public SimpleButtonMenuVM(ButtonVM buttonVM) { 43 | this.buttonVMs = new LinkedHashSet(); 44 | this.buttonVMs.add(buttonVM); 45 | } 46 | 47 | public SimpleButtonMenuVM(Collection buttons) { 48 | this.buttonVMs = new LinkedHashSet(); 49 | this.buttonVMs.addAll(buttons); 50 | } 51 | 52 | @Override 53 | public Set getButtonVMs() { 54 | return buttonVMs; 55 | } 56 | 57 | @Override 58 | public void enable() { 59 | for (ButtonVM buttonVM : buttonVMs) { 60 | buttonVM.enable(); 61 | } 62 | } 63 | 64 | @Override 65 | public void disable() { 66 | for (ButtonVM buttonVM : buttonVMs) { 67 | buttonVM.disable(); 68 | } 69 | } 70 | 71 | public void addItem(final ButtonVM buttonVM) { 72 | if (buttonVMs.add(buttonVM)) { 73 | notifyItemAdded(buttonVM); 74 | } 75 | } 76 | 77 | public void removeItem(final ButtonVM buttonVM) { 78 | if (buttonVMs.remove(buttonVM)) { 79 | notifyItemRemoved(buttonVM); 80 | } 81 | } 82 | 83 | @Override 84 | public void registerListener(ButtonMenuVMListener listener) { 85 | this.listener = listener; 86 | } 87 | 88 | @Override 89 | public void unregisterListener(ButtonMenuVMListener listener) { 90 | if (this.listener == listener) { 91 | this.listener = null; 92 | } 93 | } 94 | 95 | private void notifyItemAdded(ButtonVM buttonVM) { 96 | if (this.listener != null) { 97 | this.listener.onButtonVMAdded(buttonVM); 98 | } 99 | } 100 | 101 | private void notifyItemRemoved(ButtonVM buttonVM) { 102 | if (this.listener != null) { 103 | this.listener.onButtonVMRemoved(buttonVM); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /library/src/test/java/com/tuenti/buttonmenu/ButtonMenuTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu; 18 | 19 | import android.view.View; 20 | import android.widget.LinearLayout.LayoutParams; 21 | import android.widget.TextView; 22 | 23 | import com.tuenti.buttonmenu.viewmodel.button.ButtonCommand; 24 | import com.tuenti.buttonmenu.viewmodel.button.ButtonVM; 25 | import com.tuenti.buttonmenu.viewmodel.button.ButtonWithCounterVM; 26 | import com.tuenti.buttonmenu.viewmodel.button.ButtonWithProgressVM; 27 | import com.tuenti.buttonmenu.viewmodel.button.SimpleButtonVM; 28 | import com.tuenti.buttonmenu.viewmodel.buttonmenu.ButtonMenuVM; 29 | import com.tuenti.buttonmenu.viewmodel.buttonmenu.OnButtonCommandExecuted; 30 | import com.tuenti.buttonmenu.viewmodel.buttonmenu.SimpleButtonMenuVM; 31 | 32 | import org.junit.Before; 33 | import org.junit.Test; 34 | import org.junit.runner.RunWith; 35 | import org.mockito.Mock; 36 | import org.mockito.MockitoAnnotations; 37 | import org.robolectric.Robolectric; 38 | import org.robolectric.RobolectricTestRunner; 39 | import org.robolectric.annotation.Config; 40 | 41 | import java.util.LinkedList; 42 | import java.util.List; 43 | 44 | import static org.junit.Assert.assertEquals; 45 | import static org.junit.Assert.assertFalse; 46 | import static org.junit.Assert.assertTrue; 47 | import static org.mockito.Mockito.mock; 48 | import static org.mockito.Mockito.never; 49 | import static org.mockito.Mockito.verify; 50 | 51 | /** 52 | * Test created to check the correctness of ButtonMenu custom view working with ButtonMenuVM implementations. 53 | * 54 | * @author "Pedro Vicente Gómez Sánchez" 55 | */ 56 | @Config(manifest = Config.NONE) 57 | @RunWith(RobolectricTestRunner.class) 58 | public class ButtonMenuTest { 59 | 60 | private static final int ANY_COUNTER_VALUE = 6; 61 | private static final double DELTA = 0.01; 62 | 63 | private List buttonVMs; 64 | private ButtonMenu buttonMenu; 65 | private SimpleButtonMenuVM buttonMenuVM; 66 | private ButtonMenuVM buttonMenuVMWithProgress; 67 | private ButtonMenuVM buttonMenuVMWithCounter; 68 | private ButtonWithCounterVM buttonVMWithCounter; 69 | private ButtonWithProgressVM buttonVMWithProgress; 70 | 71 | @Mock 72 | private ButtonCommand mockedButtonCommand1; 73 | @Mock 74 | private ButtonCommand mockedButtonCommand2; 75 | @Mock 76 | private ButtonCommand mockedButtonCommand3; 77 | 78 | @Before 79 | public void setUp() { 80 | MockitoAnnotations.initMocks(this); 81 | buttonMenu = new ButtonMenu(Robolectric.application); 82 | 83 | buttonVMs = new LinkedList(); 84 | buttonVMs.add(new SimpleButtonVM(android.R.layout.simple_list_item_1, android.R.id.text1, 85 | mockedButtonCommand1)); 86 | buttonVMs.add(new SimpleButtonVM(android.R.layout.activity_list_item, android.R.id.icon, 87 | mockedButtonCommand2)); 88 | buttonMenuVM = new SimpleButtonMenuVM(buttonVMs); 89 | 90 | buttonVMWithCounter = new ButtonWithCounterVM(android.R.layout.simple_list_item_1, 91 | true, android.R.id.text1, new int[]{android.R.id.text1}, null, ANY_COUNTER_VALUE, android.R.id.text1); 92 | buttonMenuVMWithCounter = new SimpleButtonMenuVM(buttonVMWithCounter); 93 | 94 | buttonVMWithProgress = new ButtonWithProgressVM( android.R.layout.simple_expandable_list_item_2, true, 95 | android.R.id.text1, new int[] { android.R.id.text1, android.R.id.text2 }, 96 | mockedButtonCommand1, android.R.id.text1,android.R.id.text2); 97 | buttonMenuVMWithProgress = new SimpleButtonMenuVM(buttonVMWithProgress); 98 | } 99 | 100 | @Test 101 | public void shouldBeEmptyIfNoButtonMenuVMIsAssociated() { 102 | buttonMenu.initialize(); 103 | 104 | assertEquals(0, buttonMenu.getChildCount()); 105 | } 106 | 107 | @Test 108 | public void shouldNotInflateButtonVMIfButtonMenuVmIsEmpty() { 109 | buttonMenu.setButtonMenuVM(new SimpleButtonMenuVM()); 110 | buttonMenu.initialize(); 111 | 112 | assertEquals(0, buttonMenu.getChildCount()); 113 | } 114 | 115 | @Test 116 | public void shouldInflateButtonVMs() { 117 | initializeButtonMenu(); 118 | 119 | assertEquals(2, buttonMenu.getChildCount()); 120 | } 121 | 122 | @Test 123 | public void shouldExecuteActionCommandIfButtonsAreEnabled() { 124 | initializeButtonMenu(); 125 | 126 | View view = buttonMenu.findViewById(android.R.id.text1); 127 | view.performClick(); 128 | 129 | verify(mockedButtonCommand1).execute(); 130 | } 131 | 132 | 133 | @Test 134 | public void shouldExecuteOnlyOneButtonVMCommand() { 135 | initializeButtonMenu(); 136 | 137 | View view = buttonMenu.findViewById(android.R.id.icon); 138 | view.performClick(); 139 | 140 | verify(mockedButtonCommand2).execute(); 141 | verify(mockedButtonCommand1, never()).execute(); 142 | } 143 | 144 | @Test 145 | public void shouldDisableButtonVMs() { 146 | initializeButtonMenu(); 147 | 148 | buttonMenuVM.disable(); 149 | 150 | assertFalse(buttonMenu.findViewById(android.R.id.text1).isEnabled()); 151 | assertFalse(buttonMenu.findViewById(android.R.id.icon).isEnabled()); 152 | } 153 | 154 | @Test 155 | public void shouldEnableButtonMenuVM() { 156 | initializeButtonMenu(); 157 | 158 | buttonMenuVM.disable(); 159 | buttonMenuVM.enable(); 160 | 161 | assertTrue(buttonMenu.findViewById(android.R.id.text1).isEnabled()); 162 | assertTrue(buttonMenu.findViewById(android.R.id.icon).isEnabled()); 163 | } 164 | 165 | @Test 166 | public void shouldDisableButtonsOneByOne() { 167 | initializeButtonMenu(); 168 | 169 | for (ButtonVM buttonVM : buttonMenuVM.getButtonVMs()) { 170 | buttonVM.disable(); 171 | } 172 | 173 | assertFalse(buttonMenu.findViewById(android.R.id.icon).isEnabled()); 174 | assertFalse(buttonMenu.findViewById(android.R.id.text1).isEnabled()); 175 | } 176 | 177 | @Test 178 | public void shouldNotifyOnButtonCommandExecuted() { 179 | initializeButtonMenu(); 180 | OnButtonCommandExecuted mockedOnButtonCommandExecuted = mock(OnButtonCommandExecuted.class); 181 | buttonMenu.setOnButtonCommandExecutedListener(mockedOnButtonCommandExecuted); 182 | 183 | buttonMenu.findViewById(android.R.id.text1).performClick(); 184 | 185 | verify(mockedOnButtonCommandExecuted).onActionCommandExecuted(); 186 | } 187 | 188 | @Test 189 | public void shouldReleaseButtonRemovingButtons() { 190 | initializeButtonMenu(); 191 | 192 | buttonMenu.release(); 193 | 194 | assertEquals(0, buttonMenu.getChildCount()); 195 | } 196 | 197 | @Test 198 | public void everyChildShouldHaveTheSameWeightWithCorrectSum() { 199 | initializeButtonMenu(); 200 | 201 | assertEveryChildHasTheSameWeightWithCorrectSum(); 202 | } 203 | 204 | @Test 205 | public void everyChildShouldHaveTheSameWeightWithCorrectSumAfterAddingButton() { 206 | initializeButtonMenu(); 207 | 208 | buttonMenuVM.addItem(new SimpleButtonVM(android.R.layout.simple_list_item_2, 209 | android.R.id.text2, mockedButtonCommand3)); 210 | 211 | assertEveryChildHasTheSameWeightWithCorrectSum(); 212 | } 213 | 214 | @Test 215 | public void everyChildShouldHaveTheSameWeightWithCorrectSumAfterRemovingButton() { 216 | initializeButtonMenu(); 217 | 218 | buttonMenuVM.removeItem(buttonVMs.get(0)); 219 | 220 | assertEveryChildHasTheSameWeightWithCorrectSum(); 221 | } 222 | 223 | private void assertEveryChildHasTheSameWeightWithCorrectSum() { 224 | float weightSum = 0; 225 | float commonWeight = -1; 226 | for (int i = 0; i < buttonMenu.getChildCount(); i++) { 227 | View button = buttonMenu.getChildAt(i); 228 | float buttonWeight = ((LayoutParams) button.getLayoutParams()).weight; 229 | weightSum += buttonWeight; 230 | if (commonWeight == -1) { 231 | commonWeight = buttonWeight; 232 | } else { 233 | assertEquals(commonWeight, buttonWeight, DELTA); 234 | } 235 | } 236 | assertEquals(ButtonMenu.WEIGHT_SUM, weightSum, DELTA); 237 | } 238 | 239 | @Test 240 | public void shouldUpdateCounterValue() { 241 | initializeButtonMenuWithButtonMenuVM(buttonMenuVMWithCounter); 242 | 243 | buttonVMWithCounter.setCounterValue(ANY_COUNTER_VALUE); 244 | 245 | TextView counter = (TextView) buttonMenu.findViewById(android.R.id.text1); 246 | assertEquals(ANY_COUNTER_VALUE, Integer.parseInt((String) counter.getText())); 247 | } 248 | 249 | private void initializeButtonMenu() { 250 | initializeButtonMenuWithButtonMenuVM(buttonMenuVM); 251 | } 252 | 253 | @Test 254 | public void shouldUpdateProgressValue() { 255 | initializeButtonMenuWithButtonMenuVM(buttonMenuVMWithProgress); 256 | 257 | buttonVMWithProgress.showLoading(); 258 | 259 | assertTrue(buttonVMWithProgress.isLoading()); 260 | } 261 | 262 | @Test 263 | public void shouldUpdateProgressCloseValue() { 264 | initializeButtonMenuWithButtonMenuVM(buttonMenuVMWithProgress); 265 | 266 | buttonVMWithProgress.closeLoading(); 267 | 268 | assertFalse(buttonVMWithProgress.isLoading()); 269 | } 270 | 271 | private void initializeButtonMenuWithButtonMenuVM(ButtonMenuVM buttonMenuVM) { 272 | buttonMenu.setButtonMenuVM(buttonMenuVM); 273 | buttonMenu.initialize(); 274 | } 275 | 276 | } 277 | -------------------------------------------------------------------------------- /library/src/test/java/com/tuenti/buttonmenu/animator/ScrollAnimatorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.animator; 18 | 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.mockito.ArgumentCaptor; 23 | import org.mockito.Captor; 24 | import org.mockito.Mock; 25 | import org.mockito.MockitoAnnotations; 26 | import org.mockito.Spy; 27 | import org.robolectric.RobolectricTestRunner; 28 | import org.robolectric.annotation.Config; 29 | 30 | import static org.mockito.Mockito.mock; 31 | import static org.mockito.Mockito.verify; 32 | import static org.mockito.Mockito.when; 33 | import android.view.View; 34 | import android.widget.AbsListView.OnScrollListener; 35 | import android.widget.ListView; 36 | 37 | /** 38 | * Test created to check the correctness of ScrollAnimator implementation. 39 | * 40 | * @author "Pedro Vicente Gómez Sánchez" 41 | */ 42 | @Config(manifest = Config.NONE) 43 | @RunWith(RobolectricTestRunner.class) 44 | public class ScrollAnimatorTest { 45 | 46 | private static final int ANIMATED_VIEW_HEIGHT = 100; 47 | private static final String ANIMATION_TYPE_TRANSLATION_Y = "translationY"; 48 | private static final int TOTAL_ITEM_COUNT = 10; 49 | private static final int ANY_FIRST_VISIBLE_ITEM = 2; 50 | private static final int ANY_VISIBLE_ITEM_COUNT = 3; 51 | private static final int ANY_SCROLL_ACTION = 0; 52 | private static final int HIDDEN_Y_POSITION = 0; 53 | private static final int SHOW_Y_POSITION = ANIMATED_VIEW_HEIGHT; 54 | 55 | private ScrollAnimator scrollAnimator; 56 | private OnScrollListener scrollListener; 57 | 58 | @Spy 59 | private ObjectAnimatorFactory objectAnimatorFactory; 60 | @Mock 61 | private ListView listView; 62 | @Spy 63 | private View animatedView; 64 | @Captor 65 | private ArgumentCaptor scrollListenerCaptor; 66 | 67 | @Before 68 | public void setUp() { 69 | MockitoAnnotations.initMocks(this); 70 | 71 | scrollAnimator = new ScrollAnimator(animatedView, objectAnimatorFactory); 72 | 73 | setUpListView(); 74 | } 75 | 76 | @Test 77 | public void shouldHideViewOnScrollToBottom() { 78 | scrollAnimator.configureListView(listView); 79 | 80 | scrollToBottom(); 81 | 82 | verify(objectAnimatorFactory).getObjectAnimator(animatedView, ANIMATION_TYPE_TRANSLATION_Y, SHOW_Y_POSITION); 83 | 84 | } 85 | 86 | @Test 87 | public void shouldShowViewOnScrollToBottomAndThenToTop() { 88 | scrollAnimator.configureListView(listView); 89 | 90 | scrollToBottom(); 91 | scrollToTop(); 92 | 93 | verify(objectAnimatorFactory).getObjectAnimator(animatedView, ANIMATION_TYPE_TRANSLATION_Y, 0); 94 | } 95 | 96 | @Test 97 | public void shouldNotifyAdditionalScrollListenerOnScroll() { 98 | OnScrollListener mockedScrollListener = mock(OnScrollListener.class); 99 | scrollAnimator.setAdditionalScrollListener(mockedScrollListener); 100 | scrollAnimator.configureListView(listView); 101 | 102 | scrollToAnyPosition(ANY_FIRST_VISIBLE_ITEM, ANY_VISIBLE_ITEM_COUNT, TOTAL_ITEM_COUNT); 103 | 104 | verify(mockedScrollListener).onScroll(listView, ANY_FIRST_VISIBLE_ITEM, ANY_VISIBLE_ITEM_COUNT, TOTAL_ITEM_COUNT); 105 | } 106 | 107 | @Test 108 | public void shouldNotifyAdditionalScrollListenerOnScrollStateChanged() { 109 | OnScrollListener mockedScrollListener = mock(OnScrollListener.class); 110 | scrollAnimator.setAdditionalScrollListener(mockedScrollListener); 111 | scrollAnimator.configureListView(listView); 112 | 113 | doAnyScrollAction(); 114 | 115 | verify(mockedScrollListener).onScrollStateChanged(listView, ANY_SCROLL_ACTION); 116 | } 117 | 118 | @Test 119 | public void shouldReleaseListViewScrollListener() { 120 | scrollAnimator.configureListView(listView); 121 | 122 | scrollAnimator.release(); 123 | 124 | verify(listView).setOnScrollListener(null); 125 | } 126 | 127 | @Test 128 | public void shouldShowAnimatedView() { 129 | scrollAnimator.configureListView(listView); 130 | 131 | scrollAnimator.showWithAnimation(); 132 | 133 | verify(objectAnimatorFactory).getObjectAnimator(animatedView, ANIMATION_TYPE_TRANSLATION_Y, HIDDEN_Y_POSITION); 134 | } 135 | 136 | @Test 137 | public void shouldHideAnimatedView() { 138 | scrollAnimator.configureListView(listView); 139 | 140 | scrollAnimator.hideWithAnimation(); 141 | 142 | verify(objectAnimatorFactory).getObjectAnimator(animatedView, ANIMATION_TYPE_TRANSLATION_Y, SHOW_Y_POSITION); 143 | } 144 | 145 | private void scrollToBottom() { 146 | when(listView.getFirstVisiblePosition()).thenReturn(2); 147 | verify(listView).setOnScrollListener(scrollListenerCaptor.capture()); 148 | scrollListener = scrollListenerCaptor.getValue(); 149 | scrollListener.onScroll(listView, 0, 5, TOTAL_ITEM_COUNT); 150 | } 151 | 152 | 153 | private void scrollToTop() { 154 | when(listView.getFirstVisiblePosition()).thenReturn(1); 155 | verify(listView).setOnScrollListener(scrollListenerCaptor.capture()); 156 | scrollListener = scrollListenerCaptor.getValue(); 157 | scrollListener.onScroll(listView, 5, 0, TOTAL_ITEM_COUNT); 158 | } 159 | 160 | private void scrollToAnyPosition(int firstVisibleItem, int visibleItemCount, int totalItemCount) { 161 | when(listView.getFirstVisiblePosition()).thenReturn(2); 162 | verify(listView).setOnScrollListener(scrollListenerCaptor.capture()); 163 | scrollListener = scrollListenerCaptor.getValue(); 164 | scrollListener.onScroll(listView, firstVisibleItem, visibleItemCount, totalItemCount); 165 | } 166 | 167 | private void doAnyScrollAction() { 168 | verify(listView).setOnScrollListener(scrollListenerCaptor.capture()); 169 | scrollListener = scrollListenerCaptor.getValue(); 170 | scrollListener.onScrollStateChanged(listView, ANY_SCROLL_ACTION); 171 | } 172 | 173 | private void setUpListView() { 174 | View topChild = mock(View.class); 175 | when(topChild.getHeight()).thenReturn(ANIMATED_VIEW_HEIGHT); 176 | when(animatedView.getHeight()).thenReturn(ANIMATED_VIEW_HEIGHT); 177 | when(topChild.getTop()).thenReturn(1); 178 | when(listView.getChildAt(0)).thenReturn(topChild); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /library/src/test/java/com/tuenti/buttonmenu/viewmodel/button/ButtonVMTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.mockito.Mock; 22 | import org.mockito.MockitoAnnotations; 23 | 24 | import static junit.framework.Assert.assertEquals; 25 | import static junit.framework.Assert.assertFalse; 26 | import static junit.framework.Assert.assertTrue; 27 | import static org.mockito.Mockito.times; 28 | import static org.mockito.Mockito.verify; 29 | 30 | /** 31 | * Test created to check the correctness of ButtonVM implementation. Every ButtonVM implementation should pass this 32 | * tests. 33 | * 34 | * @author "Pedro Vicente Gómez Sánchez" 35 | */ 36 | public abstract class ButtonVMTest { 37 | 38 | protected static final int DEFAULT_LAYOUT_ID = 0; 39 | protected static final boolean DEFAULT_ENABLED_VALUE = true; 40 | protected static final int DEFAULT_CLICKABLE_RES_ID = 1; 41 | protected static final int[] DEFAULT_ENABLE_DISABLES_RES_IDS = {2}; 42 | 43 | protected ButtonVM buttonVM; 44 | 45 | @Mock 46 | protected ButtonCommand mockedButtonCommand; 47 | @Mock 48 | protected ButtonVMListener mockedButtonVMListener; 49 | 50 | @Before 51 | public void setUp() { 52 | MockitoAnnotations.initMocks(this); 53 | buttonVM = getButtonVM(); 54 | } 55 | 56 | @Test 57 | public void shouldContainsDefaultLayoutId() { 58 | assertEquals(DEFAULT_LAYOUT_ID, buttonVM.getLayoutId()); 59 | } 60 | 61 | @Test 62 | public void shouldBeEnabledByDefault() { 63 | assertEquals(DEFAULT_ENABLED_VALUE, buttonVM.isEnabled()); 64 | } 65 | 66 | @Test 67 | public void shouldContainDefaultClickableResId() { 68 | assertEquals(DEFAULT_CLICKABLE_RES_ID, buttonVM.getClickableResId()); 69 | } 70 | 71 | @Test 72 | public void shouldContainsDefaultEnableDisableResIds() { 73 | assertEquals(DEFAULT_ENABLE_DISABLES_RES_IDS, buttonVM.getViewIdsToEnableOrDisable()); 74 | } 75 | 76 | @Test 77 | public void shouldHaveDefaultActionCommandSet() { 78 | assertEquals(mockedButtonCommand, buttonVM.getButtonCommand()); 79 | } 80 | 81 | @Test 82 | public void shouldDisableSimpleButtonVM() { 83 | buttonVM.disable(); 84 | 85 | assertFalse(buttonVM.isEnabled()); 86 | } 87 | 88 | @Test 89 | public void shouldEnableSimpleButtonVM() { 90 | buttonVM.disable(); 91 | 92 | buttonVM.enable(); 93 | 94 | assertTrue(buttonVM.isEnabled()); 95 | } 96 | 97 | @Test 98 | public void shouldNotifyButtonVMListenerWhenEnable() { 99 | buttonVM.registerListener(mockedButtonVMListener); 100 | 101 | buttonVM.enable(); 102 | 103 | verify(mockedButtonVMListener, times(1)).onEnablePropertyChanged(true, buttonVM); 104 | } 105 | 106 | @Test 107 | public void shouldNotifyButtonVMListenerWhenDisable() { 108 | buttonVM.registerListener(mockedButtonVMListener); 109 | 110 | buttonVM.disable(); 111 | 112 | verify(mockedButtonVMListener).onEnablePropertyChanged(false, buttonVM); 113 | } 114 | 115 | protected abstract ButtonVM getButtonVM(); 116 | 117 | } 118 | -------------------------------------------------------------------------------- /library/src/test/java/com/tuenti/buttonmenu/viewmodel/button/ButtonWithCounterVMTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | import org.junit.Test; 20 | 21 | import static junit.framework.Assert.assertEquals; 22 | import static org.mockito.Mockito.times; 23 | import static org.mockito.Mockito.verify; 24 | 25 | /** 26 | * Test created to check the correctness of ButtonWithCounterVM. 27 | * 28 | * @author "Pedro Vicente Gómez Sánchez" 29 | */ 30 | public class ButtonWithCounterVMTest extends ButtonVMTest { 31 | 32 | private static final int DEFAULT_COUNTER_VALUE = 3; 33 | private static final int DEFAULT_COUNTER_WIDGET_ID = 4; 34 | private static final int ANY_OTHER_COUNTER_VALUE = 9; 35 | 36 | @Override 37 | protected ButtonVM getButtonVM() { 38 | return new ButtonWithCounterVM(DEFAULT_LAYOUT_ID, DEFAULT_ENABLED_VALUE, 39 | DEFAULT_CLICKABLE_RES_ID, 40 | DEFAULT_ENABLE_DISABLES_RES_IDS, mockedButtonCommand, DEFAULT_COUNTER_VALUE, 41 | DEFAULT_COUNTER_WIDGET_ID); 42 | } 43 | 44 | @Test 45 | public void shouldContainsDefaultCounterId() { 46 | ButtonWithCounterVM buttonWithCounterVM = (ButtonWithCounterVM) buttonVM; 47 | 48 | assertEquals(DEFAULT_COUNTER_VALUE, buttonWithCounterVM.getCounterValue()); 49 | } 50 | 51 | @Test 52 | public void shouldContainsDefaultCounterWidgetResourceId() { 53 | ButtonWithCounterVM buttonWithCounterVM = (ButtonWithCounterVM) buttonVM; 54 | 55 | assertEquals(DEFAULT_COUNTER_WIDGET_ID, buttonWithCounterVM.getCounterWidgetId()); 56 | } 57 | 58 | @Test 59 | public void shouldChangeCounterValue() { 60 | ButtonWithCounterVM buttonWithCounterVM = (ButtonWithCounterVM) buttonVM; 61 | 62 | buttonWithCounterVM.setCounterValue(ANY_OTHER_COUNTER_VALUE); 63 | 64 | assertEquals(ANY_OTHER_COUNTER_VALUE, buttonWithCounterVM.getCounterValue()); 65 | } 66 | 67 | @Test 68 | public void shouldNotifyButtonVMListener() { 69 | ButtonWithCounterVM buttonWithCounterVM = (ButtonWithCounterVM) buttonVM; 70 | buttonWithCounterVM.registerListener(mockedButtonVMListener); 71 | 72 | buttonWithCounterVM.setCounterValue(ANY_OTHER_COUNTER_VALUE); 73 | 74 | verify(mockedButtonVMListener, times(1)).onCounterValueChanged(ANY_OTHER_COUNTER_VALUE, buttonWithCounterVM); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /library/src/test/java/com/tuenti/buttonmenu/viewmodel/button/ButtonWithMutableSubjectAndResourceVMTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | 20 | import org.junit.Test; 21 | 22 | import static junit.framework.Assert.assertEquals; 23 | import static org.mockito.Mockito.verify; 24 | 25 | /** 26 | * Test created to check the correctness of ButtonWithMutableSubjectAndResourceVM. 27 | * 28 | * @author "Pedro Vicente Gómez Sánchez" 29 | */ 30 | public class ButtonWithMutableSubjectAndResourceVMTest extends ButtonWithMutableSubjectVMTest { 31 | 32 | private static final int DEFAULT_IMAGE_RESOURCE_ID = 11; 33 | private static final int ANY_IMAGE_ID = 12; 34 | 35 | @Override 36 | protected ButtonVM getButtonVM() { 37 | return new ButtonWithMutableSubjectAndResourceVM(DEFAULT_LAYOUT_ID, DEFAULT_ENABLED_VALUE, 38 | DEFAULT_CLICKABLE_RES_ID, DEFAULT_ENABLE_DISABLES_RES_IDS, mockedButtonCommand, DEFAULT_IMAGE_RESOURCE_ID, 39 | DEFAULT_SUBJECT_WIDGET_ID); 40 | } 41 | 42 | @Test 43 | public void shouldContainsDefaultResourceWidgetResourceId() { 44 | MutableResourceButtonVM buttonWithMutableResource = (MutableResourceButtonVM) buttonVM; 45 | 46 | assertEquals(DEFAULT_IMAGE_RESOURCE_ID, buttonWithMutableResource.getResIdToChangeResource()); 47 | } 48 | 49 | @Test 50 | public void shouldChangeSubjectValue() { 51 | MutableResourceButtonVM buttonWithMutableResource = (MutableResourceButtonVM) buttonVM; 52 | 53 | buttonWithMutableResource.setImageResourceId(ANY_IMAGE_ID); 54 | 55 | assertEquals(ANY_IMAGE_ID, buttonWithMutableResource.getImageResourceId()); 56 | } 57 | 58 | @Test 59 | public void shouldNotifyButtonVMListener() { 60 | MutableResourceButtonVM buttonWithMutableResource = (MutableResourceButtonVM) buttonVM; 61 | buttonWithMutableResource.registerListener(mockedButtonVMListener); 62 | 63 | buttonWithMutableResource.setImageResourceId(ANY_IMAGE_ID); 64 | 65 | verify(mockedButtonVMListener).onImageResourceChanged(ANY_IMAGE_ID, buttonWithMutableResource); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /library/src/test/java/com/tuenti/buttonmenu/viewmodel/button/ButtonWithMutableSubjectVMTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | 20 | import org.junit.Test; 21 | 22 | import static junit.framework.Assert.assertEquals; 23 | import static org.mockito.Mockito.verify; 24 | 25 | /** 26 | * Test created to check the correctness of ButtonWithMutableSubjectVM. 27 | * 28 | * @author "Pedro Vicente Gómez Sánchez" 29 | */ 30 | public class ButtonWithMutableSubjectVMTest extends ButtonVMTest { 31 | 32 | protected static final int DEFAULT_SUBJECT_WIDGET_ID = 4; 33 | private static final String ANY_SUBJECT = "pgomez@tuenti.com"; 34 | 35 | @Override 36 | protected ButtonVM getButtonVM() { 37 | return new ButtonWithMutableSubjectVM(DEFAULT_LAYOUT_ID, DEFAULT_ENABLED_VALUE, DEFAULT_CLICKABLE_RES_ID, 38 | DEFAULT_ENABLE_DISABLES_RES_IDS, DEFAULT_SUBJECT_WIDGET_ID, mockedButtonCommand); 39 | } 40 | 41 | @Test 42 | public void shouldContainsDefaultSubjectWidgetResourceId() { 43 | MutableSubjectButtonVM buttonWithMutableSubjectVM = (MutableSubjectButtonVM) buttonVM; 44 | 45 | assertEquals(DEFAULT_SUBJECT_WIDGET_ID, buttonWithMutableSubjectVM.getResIdToInsertSubject()); 46 | } 47 | 48 | @Test 49 | public void shouldChangeSubjectValue() { 50 | MutableSubjectButtonVM buttonWithMutableSubjectVM = (MutableSubjectButtonVM) buttonVM; 51 | 52 | buttonWithMutableSubjectVM.setSubject(ANY_SUBJECT); 53 | 54 | assertEquals(ANY_SUBJECT, buttonWithMutableSubjectVM.getSubject()); 55 | } 56 | 57 | @Test 58 | public void shouldNotifyButtonVMListener() { 59 | MutableSubjectButtonVM buttonWithMutableSubjectVM = (MutableSubjectButtonVM) buttonVM; 60 | buttonWithMutableSubjectVM.registerListener(mockedButtonVMListener); 61 | 62 | buttonWithMutableSubjectVM.setSubject(ANY_SUBJECT); 63 | 64 | verify(mockedButtonVMListener).onSubjectChanged(ANY_SUBJECT, buttonWithMutableSubjectVM); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /library/src/test/java/com/tuenti/buttonmenu/viewmodel/button/ButtonWithProgressVMTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.button; 18 | 19 | import org.junit.Test; 20 | 21 | import static junit.framework.Assert.assertEquals; 22 | import static junit.framework.Assert.assertTrue; 23 | import static junit.framework.Assert.assertFalse; 24 | import static org.mockito.Mockito.verify; 25 | 26 | /** 27 | * Test created to check the correctness of ButtonWithProgressVM. 28 | * 29 | * @author "Iñaki Villar Algaba" 30 | */ 31 | public class ButtonWithProgressVMTest extends ButtonVMTest { 32 | 33 | protected static final int DEFAULT_IMAGE_ID = 5; 34 | protected static final int DEFAULT_PROGRESS_IMAGE_ID = 6; 35 | 36 | @Override 37 | protected ButtonVM getButtonVM() { 38 | return new ButtonWithProgressVM(DEFAULT_LAYOUT_ID, DEFAULT_ENABLED_VALUE, 39 | DEFAULT_CLICKABLE_RES_ID, 40 | DEFAULT_ENABLE_DISABLES_RES_IDS, mockedButtonCommand, DEFAULT_IMAGE_ID, 41 | DEFAULT_PROGRESS_IMAGE_ID); 42 | } 43 | 44 | @Test 45 | public void shouldContainsDefaultSubjectWidgetResourceId() { 46 | ButtonWithProgressVM buttonWithProgressVM = (ButtonWithProgressVM) buttonVM; 47 | 48 | assertEquals(DEFAULT_IMAGE_ID, buttonWithProgressVM.getImage()); 49 | assertEquals(DEFAULT_PROGRESS_IMAGE_ID, buttonWithProgressVM.getProgress()); 50 | } 51 | 52 | @Test 53 | public void shouldChangeProgressStartValue() { 54 | ButtonWithProgressVM buttonWithMutableSubjectVM = (ButtonWithProgressVM) buttonVM; 55 | 56 | buttonWithMutableSubjectVM.showLoading(); 57 | 58 | assertTrue(buttonWithMutableSubjectVM.isLoading()); 59 | } 60 | 61 | @Test 62 | public void shouldChangeProgressFinishValue() { 63 | ButtonWithProgressVM buttonWithMutableSubjectVM = (ButtonWithProgressVM) buttonVM; 64 | 65 | buttonWithMutableSubjectVM.closeLoading(); 66 | 67 | assertFalse(buttonWithMutableSubjectVM.isLoading()); 68 | } 69 | 70 | @Test 71 | public void shouldNotifyButtonVMListener() { 72 | ButtonWithProgressVM buttonWithProgressVM = (ButtonWithProgressVM) buttonVM; 73 | buttonWithProgressVM.registerListener(mockedButtonVMListener); 74 | 75 | buttonWithProgressVM.showLoading(); 76 | 77 | verify(mockedButtonVMListener).onProgressValueChanged(true, 78 | buttonWithProgressVM); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /library/src/test/java/com/tuenti/buttonmenu/viewmodel/button/SimpleButtonVMTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.tuenti.buttonmenu.viewmodel.button; 19 | 20 | /** 21 | * Test created to check the correctness of SimpleButtonVM implementation. 22 | * 23 | * @author "Pedro Vicente Gómez Sánchez" 24 | */ 25 | public class SimpleButtonVMTest extends ButtonVMTest { 26 | 27 | @Override 28 | protected ButtonVM getButtonVM() { 29 | return new SimpleButtonVM(DEFAULT_LAYOUT_ID, DEFAULT_ENABLED_VALUE, DEFAULT_CLICKABLE_RES_ID, 30 | DEFAULT_ENABLE_DISABLES_RES_IDS, mockedButtonCommand); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /library/src/test/java/com/tuenti/buttonmenu/viewmodel/buttonmenu/SimpleButtonMenuVMTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Tuenti Technologies S.L. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tuenti.buttonmenu.viewmodel.buttonmenu; 18 | 19 | 20 | import java.util.Set; 21 | 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | import org.mockito.Mock; 25 | import org.mockito.MockitoAnnotations; 26 | 27 | import static org.junit.Assert.assertEquals; 28 | import static org.junit.Assert.assertTrue; 29 | 30 | import com.tuenti.buttonmenu.viewmodel.button.ButtonVM; 31 | 32 | /** 33 | * Test created to check the correctness of SimpleButtonMenuVM. 34 | * 35 | * @author "Pedro Vicente Gómez Sánchez" 36 | */ 37 | public class SimpleButtonMenuVMTest { 38 | 39 | private SimpleButtonMenuVM simpleButtonMenuVM; 40 | 41 | @Mock 42 | private ButtonVM mockedButtonVM; 43 | 44 | @Before 45 | public void setUp() { 46 | MockitoAnnotations.initMocks(this); 47 | initializeSimpleButtonMenuVM(); 48 | } 49 | 50 | @Test 51 | public void shouldBeEmptyAfterConstruction() { 52 | assertTrue(simpleButtonMenuVM.getButtonVMs().isEmpty()); 53 | } 54 | 55 | 56 | @Test 57 | public void shouldContainsAllTheAddedButtonVM() { 58 | simpleButtonMenuVM.addItem(mockedButtonVM); 59 | 60 | Set buttonVMs = simpleButtonMenuVM.getButtonVMs(); 61 | 62 | assertEquals(1, buttonVMs.size()); 63 | assertTrue(buttonVMs.contains(mockedButtonVM)); 64 | } 65 | 66 | @Test 67 | public void shouldContainsNoRepeatedElements() { 68 | simpleButtonMenuVM.addItem(mockedButtonVM); 69 | simpleButtonMenuVM.addItem(mockedButtonVM); 70 | 71 | Set buttonVMs = simpleButtonMenuVM.getButtonVMs(); 72 | 73 | assertEquals(1, buttonVMs.size()); 74 | assertTrue(buttonVMs.contains(mockedButtonVM)); 75 | } 76 | 77 | private void initializeSimpleButtonMenuVM() { 78 | simpleButtonMenuVM = new SimpleButtonMenuVM(); 79 | } 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | ButtonMenu - Parent 6 | Android Custom View created to work with button menus easily. 7 | http://github.com/tuenti/ButtonMenu/ 8 | 2014 9 | 10 | Tuenti Technologies S.L. 11 | http://corporate.tuenti.com/es/dev/blog 12 | 13 | 14 | library 15 | sample 16 | 17 | 18 | com.tuenti.buttonmenu 19 | buttonmenu-parent 20 | 1.0.10-SNAPSHOT 21 | pom 22 | 23 | 24 | org.sonatype.oss 25 | oss-parent 26 | 7 27 | 28 | 29 | 30 | 31 | UTF-8 32 | 4.1.1.4 33 | 3.9.0-rc.3 34 | 4.11 35 | 2.3 36 | 1.1.1 37 | 2.1.1 38 | 1.1.1 39 | 2.4.0 40 | 1.9.5 41 | 42 | 43 | 44 | 45 | 46 | 47 | com.tuenti.buttonmenu 48 | library 49 | ${project.version} 50 | jar 51 | 52 | 53 | 54 | junit 55 | junit 56 | ${junit.version} 57 | test 58 | 59 | 60 | 61 | com.google.android 62 | android 63 | ${android.version} 64 | provided 65 | 66 | 67 | 68 | com.google.android 69 | android-test 70 | ${android.version} 71 | test 72 | 73 | 74 | 75 | org.robolectric 76 | robolectric 77 | ${robolectric.version} 78 | test 79 | 80 | 81 | 82 | org.mockito 83 | mockito-all 84 | ${mockito-all.version} 85 | 86 | 87 | 88 | com.github.pedrovgs 89 | renderers 90 | ${renderers.version} 91 | 92 | 93 | 94 | com.squareup.picasso 95 | picasso 96 | ${picasso.version} 97 | 98 | 99 | 100 | com.nineoldandroids 101 | library 102 | ${library.version} 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | com.google.android 111 | android 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | com.jayway.maven.plugins.android.generation2 120 | android-maven-plugin 121 | ${android-maven-plugin.version} 122 | 123 | 124 | 18 125 | 126 | true 127 | 128 | 129 | 130 | org.apache.maven.plugins 131 | maven-gpg-plugin 132 | 133 | 134 | sign-artifacts 135 | verify 136 | 137 | sign 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | Apache 2.0 149 | http://www.apache.org/licenses/LICENSE-2.0.txt 150 | 151 | 152 | 153 | 154 | https://github.com/tuenti/ButtonMenu/ 155 | scm:git:git://github.com/tuenti/ButtonMenu.git 156 | scm:git:git@github.com:tuenti/ButtonMenu.git 157 | 1.0.0 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /sample/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | com.tuenti.buttonmenu 7 | buttonmenu-parent 8 | 1.0.10-SNAPSHOT 9 | 10 | 11 | sample 12 | apk 13 | 14 | ButtonMenu - Sample 15 | 16 | 17 | 18 | 19 | com.tuenti.buttonmenu 20 | library 21 | 22 | 23 | 24 | com.github.pedrovgs 25 | renderers 26 | 27 | 28 | 29 | 30 | com.squareup.picasso 31 | picasso 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | com.jayway.maven.plugins.android.generation2 41 | android-maven-plugin 42 | true 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /sample/res/drawable-hdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-hdpi/app_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-hdpi/contact_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-hdpi/contact_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-hdpi/moment_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-hdpi/moment_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-hdpi/photo_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-hdpi/photo_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-hdpi/refresh_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-hdpi/refresh_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-mdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-mdpi/app_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-mdpi/contact_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-mdpi/contact_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-mdpi/moment_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-mdpi/moment_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-mdpi/photo_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-mdpi/photo_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-mdpi/refresh_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-mdpi/refresh_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-xhdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-xhdpi/app_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-xhdpi/contact_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-xhdpi/contact_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-xhdpi/moment_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-xhdpi/moment_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-xhdpi/photo_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-xhdpi/photo_icon.png -------------------------------------------------------------------------------- /sample/res/drawable-xhdpi/refresh_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuenti/ButtonMenu/95791383f6f976933496542b54e8c6dbdd73e669/sample/res/drawable-xhdpi/refresh_icon.png -------------------------------------------------------------------------------- /sample/res/drawable/button_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /sample/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /sample/res/layout/activity_second.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 |