├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
├── release
│ └── bottomsheet-v1.2.3.apk
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── org
│ │ └── michaelbel
│ │ └── sample
│ │ ├── activity
│ │ └── MainActivity.java
│ │ └── fragment
│ │ └── MainFragment.java
│ └── res
│ ├── drawable-v21
│ └── selectable_custom.xml
│ ├── drawable
│ ├── ic_about.xml
│ ├── ic_copy.xml
│ ├── ic_copy_48.xml
│ ├── ic_edit.xml
│ ├── ic_facebook.xml
│ ├── ic_github.xml
│ ├── ic_gmail.xml
│ ├── ic_google_plus.xml
│ ├── ic_hangouts.xml
│ ├── ic_mail.xml
│ ├── ic_message.xml
│ ├── ic_print.xml
│ ├── ic_share.xml
│ ├── ic_theme.xml
│ ├── ic_twitter.xml
│ ├── ic_upload.xml
│ └── selectable_custom.xml
│ ├── layout
│ ├── about_view.xml
│ ├── activity_main.xml
│ └── fragment_main.xml
│ ├── menu
│ ├── menu_items.xml
│ └── menu_items_icons.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── bottomsheet
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── org
│ │ └── michaelbel
│ │ └── bottomsheet
│ │ ├── BottomSheet.java
│ │ ├── BottomSheetCallback.java
│ │ ├── BottomSheetCell.java
│ │ ├── BottomSheetGrid.java
│ │ ├── BottomSheetItem.java
│ │ ├── Utils.java
│ │ ├── annotation
│ │ ├── Beta.java
│ │ └── New.java
│ │ └── menu
│ │ ├── BottomSheetMenu.java
│ │ └── BottomSheetMenuItem.java
│ └── res
│ ├── anim
│ └── no_animation.xml
│ ├── drawable-hdpi
│ └── sheet_shadow.9.png
│ ├── drawable-mdpi
│ └── sheet_shadow.9.png
│ ├── drawable-v21
│ ├── selectable_dark.xml
│ └── selectable_light.xml
│ ├── drawable-xhdpi
│ └── sheet_shadow.9.png
│ ├── drawable-xxhdpi
│ └── sheet_shadow.9.png
│ ├── drawable-xxxhdpi
│ └── sheet_shadow.9.png
│ ├── drawable
│ ├── selectable_dark.xml
│ ├── selectable_light.xml
│ └── transparent.xml
│ ├── values-sw600dp
│ └── values.xml
│ ├── values-sw720dp
│ └── values.xml
│ ├── values-v21
│ └── styles.xml
│ └── values
│ ├── styles.xml
│ └── values.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── screenshots
├── bs_dark_1.png
├── bs_dark_2.png
├── bs_dark_3.png
├── bs_dark_4.png
├── bs_dark_landscape.png
├── bs_light_1.png
├── bs_light_2.png
├── bs_light_3.png
├── bs_light_4.png
├── bs_light_landscape.png
├── demo-gif.gif
├── direct-apk-download.png
├── web1024x500.png
├── web512x512.png
├── wiki_bs_dividers_1.jpg
├── wiki_bs_dividers_2.jpg
├── wiki_bs_fullwidth_1.jpg
└── wiki_bs_fullwidth_2.jpg
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [apk-url]: https://github.com/michaelbel/BottomSheet/raw/master/app/release/bottomsheet-v1.2.3.apk
2 | [wiki-url]: https://github.com/michaelbel/BottomSheet/wiki/usage
3 | [paypal-url]: https://paypal.me/michaelbel
4 | [github-url]: https://github.com/michaelbel/bottomsheet
5 | [licence-url]: http://www.apache.org/licenses/LICENSE-2.0
6 | [bintray-url]: https://bintray.com/michael-bel/maven/bottomsheet/_latestVersion
7 | [arsenal-url]: https://android-arsenal.com/details/1/6623
8 | [mdguides-url]: https://material.io/guidelines/components/bottom-sheets.html#
9 | [googleplay-url]: https://play.google.com/store/apps/details?id=org.michaelbel.bottomsheetdialog
10 | [methodscount-url]: http://www.methodscount.com/?lib=org.michaelbel%3Abottomsheet%3A1.1.2
11 | [bsdf-url]: https://developer.android.com/reference/android/support/design/widget/BottomSheetDialogFragment
12 |
13 | [ide-badge]: https://img.shields.io/badge/Android_Studio-3.1.4-009688.svg
14 | [minsdk-badge]: https://img.shields.io/badge/minSdkVersion-21-009688.svg
15 | [paypal-badge]: https://img.shields.io/badge/Donate-Paypal-009688.svg
16 | [license-badge]: https://img.shields.io/badge/License-Apache_v2.0-009688.svg
17 | [arsenal-badge]: https://img.shields.io/badge/Android%20Arsenal-BottomSheet-009688.svg?style=flat
18 | [bintray-badge]: https://api.bintray.com/packages/michael-bel/maven/bottomsheet/images/download.svg
19 | [platform-badge]: https://img.shields.io/badge/Platform-Android-009688.svg
20 | [googleplay-badge]: https://img.shields.io/badge/Google_Play-Demo-009688.svg
21 | [methodscount-badge]: https://img.shields.io/badge/Methods_and_Size-355_%20%7C%20_55KB-009688.svg
22 |
23 |
24 |
25 | # BottomSheet
26 | [![Bintray][bintray-badge]][bintray-url]
27 | [![Platform][platform-badge]][github-url]
28 | [![MinSdk][minsdk-badge]][github-url]
29 | [![IDE][ide-badge]][github-url]
30 | [![License][license-badge]][licence-url]
31 | [![AndroidArsenal][arsenal-badge]][arsenal-url]
32 | [![GooglePlay][googleplay-badge]][googleplay-url]
33 | [![Methodscount][methodscount-badge]][methodscount-url]
34 | [![Paypal][paypal-badge]][paypal-url]
35 |
36 | BottomSheet dialogs library for Android with [material design concept][mdguides-url].
37 | Bottom sheets slide up from the bottom of the screen to reveal more content.
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | ## Demo
58 | [](https://play.google.com/store/apps/details?id=org.michaelbel.bottomsheetdialog)
59 | [](https://github.com/michaelbel/BottomSheet/raw/master/app/release/bottomsheet-v1.2.3.apk)
60 |
61 | ## Download
62 | ```gradle
63 | dependencies {
64 | implementation 'org.michaelbel:bottomsheet:1.2.3'
65 | }
66 | ```
67 |
68 | ## Usage
69 | ```java
70 | BottomSheet.Builder builder = new BottomSheet.Builder(context);
71 | builder
72 | .setTitle(CharSequence title)
73 | .setItems(CharSequence[] items, Drawable[] icons, DialogInterface.OnClickListener listener)
74 | .setMenu(@MenuRes int menuResId, DialogInterface.OnClickListener listener)
75 | .setView(@LayoutRes int layoutResId)
76 | .setContentType(@BottomSheet.Type int type)
77 | .setDarkTheme(boolean darkTheme)
78 | .setFullWidth(boolean fullWidth)
79 | .setCellHeight(int cellHeightDp)
80 | .setDividers(boolean dividers)
81 | .setWindowDimming(@Range(from = 0, to = 255) int windowDimming)
82 | .setTitleMultiline(boolean multiline)
83 | .setFabBehavior(FloatingActionButton button)
84 | .setFabBehavior(FloatingActionButton button, @BottomSheet.FabBehavior int fabBehavior)
85 | .setBackgroundColor(@ColorInt int color)
86 | .setBackgroundColorRes(@ColorRes int color)
87 | .setTitleTextColor(@ColorInt int color)
88 | .setTitleTextColorRes(@ColorRes int color)
89 | .setItemTextColor(@ColorInt int color)
90 | .setItemTextColorRes(@ColorRes int color)
91 | .setIconColor(@ColorInt int color)
92 | .setIconColorRes(@ColorRes int color)
93 | .setItemSelector(int selector);
94 | .setOnShowListener(new DialogInterface.OnShowListener() {
95 | @Override
96 | public void onShow(DialogInterface dialog) {
97 | }
98 | });
99 | .setOnDismissListener(new DialogInterface.OnDismissListener() {
100 | @Override
101 | public void onDismiss(DialogInterface dialog) {
102 | }
103 | });
104 | .setCallback(new BottomSheetCallback() {
105 | @Override
106 | public void onShown() {
107 | }
108 |
109 | @Override
110 | public void onDismissed() {
111 | }
112 | })
113 | .show();
114 | ```
115 |
116 | ## Wiki
117 | For all information check [BottomSheet Wiki][wiki-url].
118 |
119 | ## Deprecated
120 | BottomSheet is deprecated. No more development will be taking place. Existing version will continue to function. Please, use [BottomSheetDialogFragment][bsdf-url] from Google instead. Thanks!
121 |
122 | ## License
123 |
124 | Copyright 2016 Michael Bely
125 |
126 | Licensed under the Apache License, Version 2.0 (the "License");
127 | you may not use this file except in compliance with the License.
128 | You may obtain a copy of the License at
129 |
130 | http://www.apache.org/licenses/LICENSE-2.0
131 |
132 | Unless required by applicable law or agreed to in writing, software
133 | distributed under the License is distributed on an "AS IS" BASIS,
134 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135 | See the License for the specific language governing permissions and
136 | limitations under the License.
137 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 |
6 | defaultConfig {
7 | applicationId "org.michaelbel.bottomsheetdialog"
8 | minSdkVersion 21
9 | targetSdkVersion 28
10 | versionCode 27
11 | versionName "1.2.4"
12 | buildConfigField "String", "VERSION_DATE", '"12 Nov 2018"'
13 | }
14 |
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 |
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 | }
27 |
28 | dependencies {
29 | implementation 'com.android.support:design:28.0.0'
30 | implementation 'com.android.support:appcompat-v7:28.0.0'
31 | implementation 'org.michaelbel:material:0.3.6'
32 | implementation project(':bottomsheet')
33 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\User\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
--------------------------------------------------------------------------------
/app/release/bottomsheet-v1.2.3.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/release/bottomsheet-v1.2.3.apk
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/org/michaelbel/sample/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package org.michaelbel.sample.activity;
2 |
3 | import android.content.Intent;
4 | import android.content.SharedPreferences;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.support.annotation.StyleRes;
8 | import android.support.design.widget.FloatingActionButton;
9 | import android.support.v7.app.AlertDialog;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.support.v7.widget.Toolbar;
12 | import android.view.LayoutInflater;
13 | import android.view.Menu;
14 | import android.view.MenuItem;
15 | import android.view.View;
16 | import android.widget.TextView;
17 |
18 | import org.michaelbel.sample.BuildConfig;
19 | import org.michaelbel.sample.R;
20 |
21 | public class MainActivity extends AppCompatActivity {
22 |
23 | public Toolbar toolbar;
24 | public FloatingActionButton fab;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_main);
30 |
31 | toolbar = findViewById(R.id.toolbar);
32 | setSupportActionBar(toolbar);
33 |
34 | fab = findViewById(R.id.fab);
35 | }
36 |
37 | @Override
38 | public void setTheme(@StyleRes int resId) {
39 | SharedPreferences prefs = getSharedPreferences("mainconfig", MODE_PRIVATE);
40 | boolean appTheme = prefs.getBoolean("theme", true);
41 | super.setTheme(appTheme ? R.style.AppThemeLight : R.style.AppThemeDark);
42 | }
43 |
44 | @Override
45 | public boolean onCreateOptionsMenu(Menu menu) {
46 | menu.add(R.string.about)
47 | .setIcon(R.drawable.ic_about)
48 | .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM)
49 | .setOnMenuItemClickListener(item -> {
50 | View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.about_view, null);
51 | TextView textView = view.findViewById(R.id.text_view);
52 | textView.setText(getString(R.string.version_build_date, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, BuildConfig.VERSION_DATE));
53 |
54 | AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
55 | builder.setTitle(R.string.about);
56 | builder.setView(view);
57 | builder.setPositiveButton(R.string.ok, null);
58 | builder.show();
59 | return true;
60 | });
61 |
62 | menu.add(R.string.view_github)
63 | .setIcon(R.drawable.ic_github)
64 | .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM)
65 | .setOnMenuItemClickListener(menuItem -> {
66 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.github_url))));
67 | return true;
68 | });
69 |
70 | menu.add(R.string.change_theme)
71 | .setIcon(R.drawable.ic_theme)
72 | .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM)
73 | .setOnMenuItemClickListener(menuItem -> {
74 | SharedPreferences prefs = getSharedPreferences("mainconfig", MODE_PRIVATE);
75 | SharedPreferences.Editor editor = prefs.edit();
76 | boolean appTheme = prefs.getBoolean("theme", true);
77 | editor.putBoolean("theme", !appTheme);
78 | editor.apply();
79 | recreate();
80 | return true;
81 | });
82 |
83 | return super.onCreateOptionsMenu(menu);
84 | }
85 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/michaelbel/sample/fragment/MainFragment.java:
--------------------------------------------------------------------------------
1 | package org.michaelbel.sample.fragment;
2 |
3 | import android.app.Activity;
4 | import android.content.SharedPreferences;
5 | import android.os.Bundle;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.app.Fragment;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.Button;
13 | import android.widget.CheckBox;
14 | import android.widget.RadioButton;
15 | import android.widget.SeekBar;
16 | import android.widget.TextView;
17 | import android.widget.Toast;
18 |
19 | import org.michaelbel.bottomsheet.BottomSheet;
20 | import org.michaelbel.bottomsheet.BottomSheetCallback;
21 | import org.michaelbel.bottomsheet.Utils;
22 | import org.michaelbel.sample.activity.MainActivity;
23 | import org.michaelbel.sample.R;
24 |
25 | public class MainFragment extends Fragment implements View.OnClickListener {
26 |
27 | private int[] items = new int[] {
28 | R.string.share,
29 | R.string.upload,
30 | R.string.copy,
31 | R.string.print_this_page
32 | };
33 |
34 | /*private int[] items = new int[] {
35 | R.string.preview,
36 | R.string.share,
37 | R.string.get_link,
38 | R.string.make_copy
39 | };*/
40 |
41 | private int[] icons = new int[] {
42 | R.drawable.ic_share,
43 | R.drawable.ic_upload,
44 | R.drawable.ic_copy,
45 | R.drawable.ic_print
46 | };
47 |
48 | private boolean theme;
49 | private MainActivity activity;
50 |
51 | private Button dialogButton;
52 |
53 | private CheckBox titleCheckBox;
54 | private CheckBox titleMultiCheckBox;
55 | private CheckBox iconsCheckBox;
56 | private CheckBox dividersCheckBox;
57 | private CheckBox fullWidthCheckBox;
58 | private CheckBox callbackCheckBox;
59 | private CheckBox fabCheckBox;
60 | private CheckBox wdCheckBox;
61 | private CheckBox chCheckBox;
62 |
63 | private RadioButton slideUpRadio;
64 | private RadioButton showHideRadio;
65 |
66 | private SeekBar wdSeekBar;
67 | private SeekBar chSeekBar;
68 |
69 | private TextView wdText;
70 | private TextView chText;
71 |
72 | @Override
73 | public void onCreate(@Nullable Bundle savedInstanceState) {
74 | super.onCreate(savedInstanceState);
75 | activity = (MainActivity) getActivity();
76 | }
77 |
78 | @Nullable
79 | @Override
80 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
81 | View view = inflater.inflate(R.layout.fragment_main, container);
82 |
83 | SharedPreferences prefs = activity.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
84 | theme = prefs.getBoolean("theme", true);
85 |
86 | dialogButton = view.findViewById(R.id.dialog_button);
87 | dialogButton.setOnClickListener(this);
88 |
89 | titleCheckBox = view.findViewById(R.id.check_title);
90 | titleMultiCheckBox = view.findViewById(R.id.check_title_multi);
91 | iconsCheckBox = view.findViewById(R.id.check_icons);
92 | dividersCheckBox = view.findViewById(R.id.check_dividers);
93 | fullWidthCheckBox = view.findViewById(R.id.check_full_width);
94 | callbackCheckBox = view.findViewById(R.id.check_callback);
95 | fabCheckBox = view.findViewById(R.id.check_fab);
96 | fabCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
97 | slideUpRadio.setEnabled(isChecked);
98 | showHideRadio.setEnabled(isChecked);
99 | });
100 | wdCheckBox = view.findViewById(R.id.check_wd);
101 | wdCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> wdSeekBar.setEnabled(isChecked));
102 | chCheckBox = view.findViewById(R.id.check_ch);
103 | chCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> chSeekBar.setEnabled(isChecked));
104 |
105 | slideUpRadio = view.findViewById(R.id.radio_slide_up);
106 | slideUpRadio.setChecked(true);
107 | slideUpRadio.setEnabled(false);
108 | slideUpRadio.setOnCheckedChangeListener((buttonView, isChecked) -> {
109 | slideUpRadio.setChecked(isChecked);
110 | showHideRadio.setChecked(!isChecked);
111 | });
112 |
113 | showHideRadio = view.findViewById(R.id.radio_show_hide);
114 | showHideRadio.setChecked(false);
115 | showHideRadio.setEnabled(false);
116 | showHideRadio.setOnCheckedChangeListener((buttonView, isChecked) -> {
117 | showHideRadio.setChecked(isChecked);
118 | slideUpRadio.setChecked(!isChecked);
119 | });
120 |
121 | wdSeekBar = view.findViewById(R.id.wd_seekbar);
122 | wdSeekBar.setEnabled(false);
123 | wdSeekBar.setMax(255);
124 | wdSeekBar.setProgress(80);
125 | wdSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
126 | @Override
127 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
128 | wdText.setText(String.valueOf(progress));
129 | }
130 |
131 | @Override
132 | public void onStartTrackingTouch(SeekBar seekBar) {}
133 |
134 | @Override
135 | public void onStopTrackingTouch(SeekBar seekBar) {}
136 | });
137 |
138 | wdText = view.findViewById(R.id.wd_text);
139 | wdText.setText(String.valueOf(wdSeekBar.getProgress()));
140 |
141 | chSeekBar = view.findViewById(R.id.ch_seekbar);
142 | chSeekBar.setEnabled(false);
143 | chSeekBar.setMax(16);
144 | chSeekBar.setProgress(0);
145 | chSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
146 | @Override
147 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
148 | chText.setText(String.valueOf(progress + 48));
149 | }
150 |
151 | @Override
152 | public void onStartTrackingTouch(SeekBar seekBar) {}
153 |
154 | @Override
155 | public void onStopTrackingTouch(SeekBar seekBar) {}
156 | });
157 |
158 | chText = view.findViewById(R.id.ch_text);
159 | chText.setText(String.valueOf(chSeekBar.getProgress() + 48));
160 |
161 | return view;
162 | }
163 |
164 | @Override
165 | public void onClick(View v) {
166 | if (v == dialogButton) {
167 | BottomSheet.Builder builder = new BottomSheet.Builder(activity);
168 | builder.setDarkTheme(!theme);
169 | if (titleCheckBox.isChecked()) {
170 | builder.setTitle(R.string.title_text);
171 | }
172 | if (titleMultiCheckBox.isChecked()) {
173 | builder.setTitle(R.string.title_multiline_text);
174 | builder.setTitleMultiline(true);
175 | }
176 | if (iconsCheckBox.isChecked()) {
177 | builder.setItems(items, icons, (dialogInterface, i) ->
178 | Toast.makeText(activity, items[i], Toast.LENGTH_SHORT).show()
179 | );
180 | } else {
181 | builder.setItems(items, (dialogInterface, i) ->
182 | Toast.makeText(activity, items[i], Toast.LENGTH_SHORT).show()
183 | );
184 | }
185 | builder.setDividers(dividersCheckBox.isChecked());
186 | builder.setFullWidth(fullWidthCheckBox.isChecked());
187 | if (callbackCheckBox.isChecked()) {
188 | builder.setCallback(new BottomSheetCallback() {
189 | @Override
190 | public void onShown() {
191 | Toast.makeText(activity, R.string.shown, Toast.LENGTH_SHORT).show();
192 | }
193 |
194 | @Override
195 | public void onDismissed() {
196 | Toast.makeText(activity, R.string.dismissed, Toast.LENGTH_SHORT).show();
197 | }
198 | });
199 | }
200 | if (fabCheckBox.isChecked()) {
201 | if (slideUpRadio.isChecked()) {
202 | builder.setFabBehavior(activity.fab, BottomSheet.FAB_SLIDE_UP);
203 | } else {
204 | builder.setFabBehavior(activity.fab);
205 | }
206 | }
207 | if (wdCheckBox.isChecked()) {
208 | builder.setWindowDimming(wdSeekBar.getProgress());
209 | }
210 | if (chCheckBox.isChecked()) {
211 | builder.setCellHeight(Utils.dp(activity, chSeekBar.getProgress() + 48));
212 | }
213 |
214 | builder.show();
215 | }
216 | }
217 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/selectable_custom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_about.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_copy.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_copy_48.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_edit.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_facebook.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_github.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_gmail.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_google_plus.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_hangouts.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_mail.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_message.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_print.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_share.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_theme.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_twitter.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_upload.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/selectable_custom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/about_view.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
14 |
15 |
22 |
23 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
18 |
19 |
20 |
21 |
28 |
29 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
14 |
15 |
16 |
22 |
23 |
24 |
30 |
31 |
32 |
38 |
39 |
40 |
46 |
47 |
48 |
54 |
55 |
56 |
62 |
63 |
64 |
70 |
71 |
72 |
78 |
79 |
84 |
85 |
91 |
92 |
98 |
99 |
100 |
101 |
102 |
108 |
109 |
113 |
114 |
120 |
121 |
128 |
129 |
130 |
131 |
132 |
138 |
139 |
143 |
144 |
150 |
151 |
158 |
159 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_items.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_items_icons.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 | #FF5252
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | BottomSheet
3 | OK
4 | About
5 | Version %1$s (Build %2$d) of %3$s
6 | https://github.com/michaelbel/bottomsheet
7 | View on Github
8 | Change Theme
9 | Show Dialog
10 | Title
11 | Title Multiline
12 | Actions
13 | This title is multiline. This means that you can place here a few lines of text
14 | Icons
15 | Dividers
16 | Full Width
17 | Callback
18 | Shown
19 | Dismissed
20 | Fab Behavior
21 | Slide
22 | Show hide
23 | Window dimming
24 | Cell height
25 | No image
26 |
27 | Message
28 | Print this page
29 | Share
30 | Upload
31 | Copy
32 | Preview
33 | Get link
34 | Make a copy
35 | Gmail
36 | Hangout
37 | Google+
38 | Mail
39 | Facebook
40 | Twitter
41 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/bottomsheet/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/bottomsheet/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: "com.jfrog.bintray"
3 | apply plugin: 'com.github.dcendents.android-maven'
4 |
5 | android {
6 | compileSdkVersion 28
7 |
8 | defaultConfig {
9 | minSdkVersion 14
10 | targetSdkVersion 28
11 | }
12 |
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 |
20 | lintOptions {
21 | abortOnError false
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation 'com.android.support:design:28.0.0'
27 | implementation 'com.android.support:appcompat-v7:28.0.0'
28 | }
29 |
30 | Properties properties = new Properties()
31 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
32 | bintray {
33 | user = properties.getProperty("bintray.user")
34 | key = properties.getProperty("bintray.apikey")
35 | configurations = ['archives']
36 | }
37 |
38 | ext {
39 | bintrayRepo = 'maven'
40 | bintrayName = 'bottomsheet'
41 |
42 | artifact = 'bottomsheet'
43 | publishedGroupId = 'org.michaelbel'
44 |
45 | libraryVersion = '1.2.4'
46 | libraryName = 'BottomSheet'
47 | libraryDescription = 'BottomSheet dialogs library for Android'
48 |
49 | siteUrl = 'https://github.com/michaelbel/bottomsheet'
50 | gitUrl = 'https://github.com/michaelbel/bottomsheet.git'
51 |
52 | developerId = 'michaelbel'
53 | developerName = 'Michael Bel'
54 | developerEmail = 'michael-bel@outlook.com'
55 |
56 | licenseName = 'The Apache Software License, Version 2.0'
57 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
58 | allLicenses = ["Apache-2.0"]
59 | }
60 |
61 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
62 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'
63 |
64 | javadoc {
65 | options {
66 | encoding = 'UTF-8'
67 | }
68 | }
69 |
70 | artifacts {
71 | archives javadocJar
72 | archives sourcesJar
73 | }
74 |
75 | allprojects {
76 | tasks.withType(Javadoc) {
77 | options.addStringOption('Xdoclint:none', '-quiet')
78 | options.addStringOption('encoding', 'UTF-8')
79 | }
80 | }
--------------------------------------------------------------------------------
/bottomsheet/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\User\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
--------------------------------------------------------------------------------
/bottomsheet/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/java/org/michaelbel/bottomsheet/BottomSheet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Michael Bely
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 org.michaelbel.bottomsheet;
18 |
19 | import android.animation.Animator;
20 | import android.animation.AnimatorListenerAdapter;
21 | import android.animation.AnimatorSet;
22 | import android.animation.ObjectAnimator;
23 | import android.annotation.SuppressLint;
24 | import android.app.Dialog;
25 | import android.content.Context;
26 | import android.content.DialogInterface;
27 | import android.graphics.Canvas;
28 | import android.graphics.Point;
29 | import android.graphics.PorterDuff;
30 | import android.graphics.PorterDuffColorFilter;
31 | import android.graphics.Rect;
32 | import android.graphics.drawable.ColorDrawable;
33 | import android.graphics.drawable.Drawable;
34 | import android.os.Build;
35 | import android.os.Bundle;
36 | import android.os.Handler;
37 | import android.os.Looper;
38 | import android.support.annotation.ArrayRes;
39 | import android.support.annotation.BoolRes;
40 | import android.support.annotation.ColorInt;
41 | import android.support.annotation.ColorRes;
42 | import android.support.annotation.IntDef;
43 | import android.support.annotation.IntRange;
44 | import android.support.annotation.LayoutRes;
45 | import android.support.annotation.MenuRes;
46 | import android.support.annotation.NonNull;
47 | import android.support.annotation.Nullable;
48 | import android.support.annotation.RestrictTo;
49 | import android.support.annotation.StringRes;
50 | import android.support.design.widget.FloatingActionButton;
51 | import android.support.v4.content.ContextCompat;
52 | import android.support.v4.view.NestedScrollingParent;
53 | import android.support.v4.view.NestedScrollingParentHelper;
54 | import android.support.v4.view.ViewCompat;
55 | import android.text.TextUtils;
56 | import android.util.DisplayMetrics;
57 | import android.util.TypedValue;
58 | import android.view.Gravity;
59 | import android.view.LayoutInflater;
60 | import android.view.Menu;
61 | import android.view.MenuInflater;
62 | import android.view.MotionEvent;
63 | import android.view.VelocityTracker;
64 | import android.view.View;
65 | import android.view.ViewConfiguration;
66 | import android.view.ViewGroup;
67 | import android.view.Window;
68 | import android.view.WindowInsets;
69 | import android.view.WindowManager;
70 | import android.view.animation.AccelerateInterpolator;
71 | import android.view.animation.DecelerateInterpolator;
72 | import android.widget.AdapterView;
73 | import android.widget.BaseAdapter;
74 | import android.widget.FrameLayout;
75 | import android.widget.GridView;
76 | import android.widget.LinearLayout;
77 | import android.widget.ListView;
78 | import android.widget.TextView;
79 |
80 | import org.michaelbel.bottomsheet.annotation.Beta;
81 | import org.michaelbel.bottomsheet.annotation.New;
82 | import org.michaelbel.bottomsheet.menu.BottomSheetMenu;
83 | import org.michaelbel.bottomsheetdialog.R;
84 |
85 | import java.lang.annotation.Retention;
86 | import java.lang.annotation.RetentionPolicy;
87 | import java.util.ArrayList;
88 | import java.util.Arrays;
89 | import java.util.Collections;
90 | import java.util.List;
91 |
92 | import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
93 |
94 | /**
95 | * Date: 17 FEB 2018
96 | * Time: 00:33 MSK
97 | *
98 | * @author Michael Bel
99 | */
100 |
101 | @SuppressWarnings("all")
102 | public class BottomSheet extends Dialog {
103 |
104 | public static final int LIST = 1;
105 | public static final int GRID = 2;
106 |
107 | public static final int LIGHT_THEME = 10;
108 | public static final int DARK_THEME = 11;
109 |
110 | public static final int FAB_SLIDE_UP = 20;
111 | public static final int FAB_SHOW_HIDE = 21;
112 |
113 | @RestrictTo(LIBRARY_GROUP)
114 | @Retention(RetentionPolicy.SOURCE)
115 | @IntDef({LIST, GRID})
116 | public @interface Type {}
117 |
118 | @RestrictTo(LIBRARY_GROUP)
119 | @Retention(RetentionPolicy.SOURCE)
120 | @IntDef({LIGHT_THEME, DARK_THEME})
121 | public @interface Theme {}
122 |
123 | @RestrictTo(LIBRARY_GROUP)
124 | @Retention(RetentionPolicy.SOURCE)
125 | @IntDef({FAB_SHOW_HIDE, FAB_SLIDE_UP})
126 | public @interface FabBehavior {}
127 |
128 | private boolean dividers;
129 | private boolean fullWidth;
130 | private boolean darkTheme;
131 | private boolean titleTextMultiline;
132 |
133 | private int cellHeight;
134 | private int itemSelector;
135 | private int dimmingValue = 80;
136 |
137 | private @Type int contentType = LIST;
138 | private @Theme int theme = LIGHT_THEME;
139 | private @FabBehavior int fabBehavior = FAB_SHOW_HIDE;
140 |
141 | private @ColorInt int titleTextColor;
142 | private @ColorInt int backgroundColor;
143 | private @ColorInt int iconColor;
144 | private @ColorInt int itemTextColor;
145 |
146 | private View customView;
147 | private TextView titleTextView;
148 | private ListView listView;
149 | private GridView gridView;
150 | private ContainerView container;
151 | private LinearLayout containerView;
152 |
153 | private List ICONS = new ArrayList<>();
154 | private List ITEMS = new ArrayList<>();
155 |
156 | private CharSequence titleText;
157 | private ArrayList bottomsheetItems = new ArrayList<>();
158 |
159 | private WindowInsets lastInsets;
160 | private Runnable startAnimationRunnable;
161 | private int layoutCount;
162 | private boolean dismissed;
163 |
164 | private ColorDrawable backDrawable = new ColorDrawable(0xFF000000);
165 | private boolean allowCustomAnimation = true;
166 | private int touchSlop;
167 | private boolean useFastDismiss;
168 | private boolean focusable;
169 | private Drawable shadowDrawable;
170 | private int backgroundPaddingTop;
171 | private int backgroundPaddingLeft;
172 | private AnimatorSet currentSheetAnimation;
173 |
174 | private Point displaySize = new Point();
175 | private DisplayMetrics metrics = new DisplayMetrics();
176 | private Handler handler = new Handler(Looper.getMainLooper());
177 |
178 | private OnClickListener onClickListener;
179 | private BottomSheetCallback bottomSheetCallback;
180 |
181 | private DialogInterface.OnShowListener onShowListener;
182 | private DialogInterface.OnDismissListener onDismissListener;
183 |
184 | private boolean allowDrawContent = true;
185 | private boolean useHardwareLayer = true;
186 |
187 | private FloatingActionButton floatingActionButton;
188 |
189 | @Override
190 | protected void onCreate(Bundle savedInstanceState) {
191 | super.onCreate(savedInstanceState);
192 |
193 | if (backgroundColor == 0) {
194 | backgroundColor = darkTheme ? 0xFF424242 : 0xFFFFFFFF;
195 | }
196 |
197 | if (titleTextColor == 0) {
198 | titleTextColor = darkTheme ? 0xB3FFFFFF : 0x8A000000;
199 | }
200 |
201 | if (itemTextColor == 0) {
202 | itemTextColor = darkTheme ? 0xFFFFFFFF : 0xDE000000;
203 | }
204 |
205 | if (iconColor == 0) {
206 | iconColor = darkTheme ? 0xFFFFFFFF : 0x8A000000;
207 | }
208 |
209 | if (itemSelector == 0) {
210 | itemSelector = darkTheme ? R.drawable.selectable_dark : R.drawable.selectable_light;
211 | }
212 |
213 | if (cellHeight == 0) {
214 | cellHeight = Utils.dp(getContext(), 48);
215 | }
216 |
217 | Window window = getWindow();
218 | if (window != null) {
219 | window.setWindowAnimations(R.style.DialogNoAnimation);
220 | }
221 | setContentView(container, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
222 |
223 | if (containerView == null) {
224 | containerView = new LinearLayout(getContext()) {
225 | @Override
226 | public boolean hasOverlappingRendering() {
227 | return false;
228 | }
229 |
230 | @Override
231 | public void setTranslationY(float translationY) {
232 | super.setTranslationY(translationY);
233 | onContainerTranslationYChanged(translationY);
234 | }
235 | };
236 | containerView.setOrientation(LinearLayout.VERTICAL);
237 | containerView.setBackgroundDrawable(shadowDrawable);
238 | containerView.setPadding(0, backgroundPaddingTop, 0, Utils.dp(getContext(), 8));
239 | }
240 |
241 | if (Build.VERSION.SDK_INT >= 21) {
242 | containerView.setFitsSystemWindows(true);
243 | }
244 |
245 | containerView.setVisibility(View.INVISIBLE);
246 | containerView.setBackgroundColor(backgroundColor);
247 |
248 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
249 | params.gravity = Gravity.BOTTOM;
250 |
251 | containerView.setLayoutParams(params);
252 | container.addView(containerView, 0);
253 |
254 | if (customView != null) {
255 | if (customView.getParent() != null) {
256 | ViewGroup viewGroup = (ViewGroup) customView.getParent();
257 | viewGroup.removeView(customView);
258 | }
259 |
260 | FrameLayout.LayoutParams params1 = (FrameLayout.LayoutParams) containerView.getLayoutParams();
261 | params1.width = ViewGroup.LayoutParams.MATCH_PARENT;
262 | params1.height = ViewGroup.LayoutParams.WRAP_CONTENT;
263 | params1.gravity = Gravity.START | Gravity.TOP;
264 | containerView.addView(customView, params1);
265 | } else {
266 | if (titleText != null) {
267 | titleTextView = new TextView(getContext());
268 | titleTextView.setLines(1);
269 | titleTextView.setText(titleText);
270 | titleTextView.setTextColor(titleTextColor);
271 | titleTextView.setGravity(Gravity.CENTER_VERTICAL);
272 | titleTextView.setEllipsize(TextUtils.TruncateAt.END);
273 | titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
274 |
275 | if (titleTextMultiline) {
276 | titleTextView.setSingleLine(false);
277 | } else {
278 | titleTextView.setMaxLines(1);
279 | titleTextView.setSingleLine(true);
280 | }
281 |
282 | LinearLayout.LayoutParams params0 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
283 | params0.gravity = Gravity.START | Gravity.TOP;
284 | params0.leftMargin = Utils.dp(getContext(), 16);
285 | params0.rightMargin = Utils.dp(getContext(), 16);
286 | params0.topMargin = Utils.dp(getContext(), 8);
287 | params0.bottomMargin = Utils.dp(getContext(), 16);
288 |
289 | titleTextView.setLayoutParams(params0);
290 | containerView.addView(titleTextView);
291 | }
292 |
293 | BottomSheetAdapter adapter = new BottomSheetAdapter();
294 |
295 | if (!ITEMS.isEmpty()) {
296 | if (contentType == LIST) {
297 | LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
298 |
299 | listView = new ListView(getContext());
300 | listView.setSelector(itemSelector);
301 | listView.setDividerHeight(0);
302 | listView.setAdapter(adapter);
303 | listView.setDrawSelectorOnTop(true);
304 | listView.setVerticalScrollBarEnabled(false);
305 | listView.setLayoutParams(params2);
306 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
307 | @Override
308 | public void onItemClick(AdapterView> adapterView, View view, int position, long l) {
309 | dismissWithButtonClick(position);
310 | }
311 | });
312 |
313 | containerView.addView(listView);
314 | } else if (contentType == GRID) {
315 | LinearLayout.LayoutParams params3 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
316 |
317 | gridView = new GridView(getContext());
318 | gridView.setSelector(itemSelector);
319 | gridView.setAdapter(adapter);
320 | gridView.setNumColumns(3);
321 | gridView.setVerticalScrollBarEnabled(false);
322 | gridView.setVerticalSpacing(Utils.dp(getContext(), 16));
323 | gridView.setPadding(Utils.dp(getContext(), 0), Utils.dp(getContext(),8), Utils.dp(getContext(), 0), Utils.dp(getContext(), 16));
324 | gridView.setLayoutParams(params3);
325 | gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
326 | @Override
327 | public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
328 | dismissWithButtonClick(i);
329 | }
330 | });
331 |
332 | containerView.addView(gridView);
333 | }
334 |
335 | if (!ITEMS.isEmpty()) {
336 | for (int a = 0; a < ITEMS.size(); a++) {
337 | bottomsheetItems.add(new BottomSheetItem(ITEMS.get(a), !ICONS.isEmpty() ? ICONS.get(a) : null));
338 | }
339 | }
340 |
341 | adapter.notifyDataSetChanged();
342 | }
343 | }
344 |
345 | WindowManager.LayoutParams params4 = window.getAttributes();
346 | params4.width = ViewGroup.LayoutParams.MATCH_PARENT;
347 | params4.gravity = Gravity.TOP | Gravity.START;
348 | params4.dimAmount = 0;
349 | params4.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND;
350 | if (!focusable) {
351 | params4.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
352 | }
353 | params4.height = ViewGroup.LayoutParams.MATCH_PARENT;
354 | window.setAttributes(params4);
355 | }
356 |
357 | @Override
358 | public void show() {
359 | super.show();
360 | if (focusable) {
361 | try {
362 | getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
363 | } catch (Exception e) {
364 | e.printStackTrace();
365 | }
366 | }
367 |
368 | dismissed = false;
369 | cancelSheetAnimation();
370 | containerView.measure(View.MeasureSpec.makeMeasureSpec(displaySize.x, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(displaySize.y, View.MeasureSpec.AT_MOST));
371 |
372 | backDrawable.setAlpha(0);
373 |
374 | if (Build.VERSION.SDK_INT >= 18) {
375 | layoutCount = 2;
376 | containerView.setTranslationY(containerView.getMeasuredHeight());
377 | handler.postDelayed(startAnimationRunnable = new Runnable() {
378 | @Override
379 | public void run() {
380 | if (startAnimationRunnable != this) {
381 | return;
382 | }
383 |
384 | startAnimationRunnable = null;
385 | startShowAnimation();
386 | }
387 | }, 150);
388 | } else {
389 | startShowAnimation();
390 | }
391 |
392 | if (bottomSheetCallback != null) {
393 | bottomSheetCallback.onShown();
394 | }
395 |
396 | if (onShowListener != null) {
397 | onShowListener.onShow(this);
398 | }
399 | }
400 |
401 | @Override
402 | public void dismiss() {
403 | dismissWithButtonClick(-1);
404 | }
405 |
406 | private void dismissWithButtonClick(final int viewId) {
407 | if (dismissed) {
408 | return;
409 | }
410 |
411 | dismissed = true;
412 | cancelSheetAnimation();
413 |
414 | AnimatorSet animatorSet = new AnimatorSet();
415 | if (floatingActionButton != null && fabBehavior == FAB_SLIDE_UP) {
416 | animatorSet.playTogether(
417 | ObjectAnimator.ofFloat(containerView, "translationY", containerView.getMeasuredHeight() + Utils.dp(getContext(), 10)),
418 | ObjectAnimator.ofInt(backDrawable, "alpha", 0),
419 | ObjectAnimator.ofFloat(floatingActionButton, "translationY", 0)
420 | );
421 | } else if (floatingActionButton == null || fabBehavior != FAB_SLIDE_UP) {
422 | animatorSet.playTogether(
423 | ObjectAnimator.ofFloat(containerView, "translationY", containerView.getMeasuredHeight() + Utils.dp(getContext(), 10)),
424 | ObjectAnimator.ofInt(backDrawable, "alpha", 0)
425 | );
426 | }
427 | animatorSet.addListener(new AnimatorListenerAdapter() {
428 | @Override
429 | public void onAnimationCancel(Animator animation) {
430 | super.onAnimationCancel(animation);
431 | if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
432 | currentSheetAnimation = null;
433 | }
434 | }
435 |
436 | @Override
437 | public void onAnimationEnd(Animator animation) {
438 | super.onAnimationEnd(animation);
439 | if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
440 | currentSheetAnimation = null;
441 |
442 | if (viewId != -1) {
443 | if (onClickListener != null) {
444 | onClickListener.onClick(BottomSheet.this, viewId);
445 | }
446 | }
447 |
448 | handler.post(new Runnable() {
449 | @Override
450 | public void run() {
451 | try {
452 | BottomSheet.super.dismiss();
453 | } catch (Exception e) {
454 | e.printStackTrace();
455 | }
456 | }
457 | });
458 | }
459 | }
460 | });
461 |
462 | if (useFastDismiss) {
463 | int height = containerView.getMeasuredHeight();
464 | animatorSet.setDuration(Math.max(60, (int) (180 * (height - containerView.getTranslationY()) / (float) height)));
465 | useFastDismiss = false;
466 | } else {
467 | animatorSet.setDuration(180);
468 | }
469 |
470 | animatorSet.setInterpolator(new AccelerateInterpolator());
471 | animatorSet.addListener(new AnimatorListenerAdapter() {
472 | @Override
473 | public void onAnimationStart(Animator animation) {
474 | super.onAnimationStart(animation);
475 | }
476 |
477 | @Override
478 | public void onAnimationEnd(Animator animation) {
479 | super.onAnimationEnd(animation);
480 | if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
481 | currentSheetAnimation = null;
482 | handler.post(new Runnable() {
483 | @Override
484 | public void run() {
485 | try {
486 | dismissInternal();
487 | } catch (Exception e) {
488 | e.printStackTrace();
489 | }
490 | }
491 | });
492 | }
493 |
494 | if (floatingActionButton != null && fabBehavior == FAB_SHOW_HIDE) {
495 | floatingActionButton.show();
496 | }
497 | }
498 |
499 | @Override
500 | public void onAnimationCancel(Animator animation) {
501 | super.onAnimationCancel(animation);
502 | if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
503 | currentSheetAnimation = null;
504 | }
505 | }
506 | });
507 |
508 | animatorSet.start();
509 | currentSheetAnimation = animatorSet;
510 |
511 | if (bottomSheetCallback != null) {
512 | bottomSheetCallback.onDismissed();
513 | }
514 |
515 | if (onDismissListener != null) {
516 | onDismissListener.onDismiss(this);
517 | }
518 | }
519 |
520 | private BottomSheet(Context context, boolean needFocus) {
521 | super(context, R.style.TransparentDialog);
522 |
523 | if (Build.VERSION.SDK_INT >= 21) {
524 | getWindow().addFlags(
525 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |
526 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
527 | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
528 | );
529 | }
530 |
531 | ViewConfiguration vc = ViewConfiguration.get(context);
532 | touchSlop = vc.getScaledTouchSlop();
533 |
534 | Rect padding = new Rect();
535 | shadowDrawable = ContextCompat.getDrawable(context, R.drawable.sheet_shadow);
536 | shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xFFFFFFFF, PorterDuff.Mode.MULTIPLY)); // todo ADDED
537 | shadowDrawable.getPadding(padding);
538 | backgroundPaddingLeft = padding.left;
539 | backgroundPaddingTop = padding.top;
540 |
541 | container = new BottomSheet.ContainerView(getContext()) {
542 | @Override
543 | public boolean drawChild(Canvas canvas, View child, long drawingTime) {
544 | try {
545 | return allowDrawContent && super.drawChild(canvas, child, drawingTime);
546 | } catch (Exception e) {
547 | e.printStackTrace();
548 | }
549 | return true;
550 | }
551 | };
552 |
553 | container.setBackgroundDrawable(backDrawable);
554 | focusable = needFocus;
555 |
556 | if (Build.VERSION.SDK_INT >= 21) {
557 | container.setFitsSystemWindows(true);
558 | container.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
559 | @SuppressLint("NewApi")
560 | @Override
561 | public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
562 | lastInsets = insets;
563 | view.requestLayout();
564 | return insets.consumeSystemWindowInsets();
565 | }
566 | });
567 | container.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
568 | }
569 |
570 | backDrawable.setAlpha(0);
571 | }
572 |
573 | private class ContainerView extends FrameLayout implements NestedScrollingParent {
574 |
575 | private int startedTrackingX;
576 | private int startedTrackingY;
577 | private int startedTrackingPointerId;
578 |
579 | private boolean maybeStartTracking = false;
580 | private boolean startedTracking = false;
581 |
582 | private AnimatorSet currentAnimation = null;
583 | private VelocityTracker velocityTracker = null;
584 | private NestedScrollingParentHelper nestedScrollingParentHelper;
585 |
586 | public ContainerView(Context context) {
587 | super(context);
588 | nestedScrollingParentHelper = new NestedScrollingParentHelper(this);
589 | }
590 |
591 | @Override
592 | public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes) {
593 | return !dismissed && axes == ViewCompat.SCROLL_AXIS_VERTICAL && !canDismissWithSwipe();
594 | }
595 |
596 | @Override
597 | public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes) {
598 | nestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
599 | if (dismissed) {
600 | return;
601 | }
602 | cancelCurrentAnimation();
603 | }
604 |
605 | @Override
606 | public void onStopNestedScroll(@NonNull View target) {
607 | nestedScrollingParentHelper.onStopNestedScroll(target);
608 | if (dismissed) {
609 | return;
610 | }
611 | checkDismiss(0, 0);
612 | }
613 |
614 | @Override
615 | public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
616 | if (dismissed) {
617 | return;
618 | }
619 |
620 | cancelCurrentAnimation();
621 |
622 | if (dyUnconsumed != 0) {
623 | float currentTranslation = containerView.getTranslationY();
624 | currentTranslation -= dyUnconsumed;
625 |
626 | if (currentTranslation < 0) {
627 | currentTranslation = 0;
628 | }
629 |
630 | containerView.setTranslationY(currentTranslation);
631 | }
632 | }
633 |
634 | @Override
635 | public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed) {
636 | if (dismissed) {
637 | return;
638 | }
639 |
640 | cancelCurrentAnimation();
641 | float currentTranslation = containerView.getTranslationY();
642 |
643 | if (currentTranslation > 0 && dy > 0) {
644 | currentTranslation -= dy;
645 | consumed[1] = dy;
646 |
647 | if (currentTranslation < 0) {
648 | currentTranslation = 0;
649 | consumed[1] += currentTranslation;
650 | }
651 |
652 | containerView.setTranslationY(currentTranslation);
653 | }
654 | }
655 |
656 | @Override
657 | public boolean onNestedFling(@NonNull View target, float velocityX, float velocityY, boolean consumed) {
658 | return false;
659 | }
660 |
661 | @Override
662 | public boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY) {
663 | return false;
664 | }
665 |
666 | @Override
667 | public int getNestedScrollAxes() {
668 | return nestedScrollingParentHelper.getNestedScrollAxes();
669 | }
670 |
671 | private void checkDismiss(float velX, float velY) {
672 | float translationY = containerView.getTranslationY();
673 | boolean backAnimation = translationY < getPixelsInCM(0.8f, false) && (velY < 3500 || Math.abs(velY) < Math.abs(velX)) || velY < 0 && Math.abs(velY) >= 3500;
674 |
675 | if (!backAnimation) {
676 | boolean allowOld = allowCustomAnimation;
677 | allowCustomAnimation = false;
678 | useFastDismiss = true;
679 | dismiss();
680 | allowCustomAnimation = allowOld;
681 | } else {
682 | currentAnimation = new AnimatorSet();
683 | currentAnimation.playTogether(ObjectAnimator.ofFloat(containerView, "translationY", 0));
684 | currentAnimation.setDuration((int) (150 * (translationY / getPixelsInCM(0.8F, false))));
685 | currentAnimation.setInterpolator(new DecelerateInterpolator());
686 | currentAnimation.addListener(new AnimatorListenerAdapter() {
687 | @Override
688 | public void onAnimationEnd(Animator animation) {
689 | super.onAnimationEnd(animation);
690 |
691 | if (currentAnimation != null && currentAnimation.equals(animation)) {
692 | currentAnimation = null;
693 | }
694 | }
695 | });
696 | currentAnimation.start();
697 | }
698 | }
699 |
700 | private void cancelCurrentAnimation() {
701 | if (currentAnimation != null) {
702 | currentAnimation.cancel();
703 | currentAnimation = null;
704 | }
705 | }
706 |
707 | @Override
708 | public boolean onTouchEvent(MotionEvent ev) {
709 | if (dismissed) {
710 | return false;
711 | }
712 | if (onContainerTouchEvent(ev)) {
713 | return true;
714 | }
715 | if (canDismissWithTouchOutside() && ev != null && (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) && !startedTracking && !maybeStartTracking) {
716 | startedTrackingX = (int) ev.getX();
717 | startedTrackingY = (int) ev.getY();
718 | if (startedTrackingY < containerView.getTop() || startedTrackingX < containerView.getLeft() || startedTrackingX > containerView.getRight()) {
719 | dismiss();
720 | return true;
721 | }
722 | startedTrackingPointerId = ev.getPointerId(0);
723 | maybeStartTracking = true;
724 | cancelCurrentAnimation();
725 | if (velocityTracker != null) {
726 | velocityTracker.clear();
727 | }
728 | } else if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && ev.getPointerId(0) == startedTrackingPointerId) {
729 | if (velocityTracker == null) {
730 | velocityTracker = VelocityTracker.obtain();
731 | }
732 | float dx = Math.abs((int) (ev.getX() - startedTrackingX));
733 | float dy = (int) ev.getY() - startedTrackingY;
734 | velocityTracker.addMovement(ev);
735 | if (maybeStartTracking && !startedTracking && (dy > 0 && dy / 3.0f > Math.abs(dx) && Math.abs(dy) >= touchSlop)) {
736 | startedTrackingY = (int) ev.getY();
737 | maybeStartTracking = false;
738 | startedTracking = true;
739 | requestDisallowInterceptTouchEvent(true);
740 | } else if (startedTracking) {
741 | float translationY = containerView.getTranslationY();
742 | translationY += dy;
743 | if (translationY < 0) {
744 | translationY = 0;
745 | }
746 | containerView.setTranslationY(translationY);
747 | startedTrackingY = (int) ev.getY();
748 | }
749 | } else if (ev == null || ev != null && ev.getPointerId(0) == startedTrackingPointerId && (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_POINTER_UP)) {
750 | if (velocityTracker == null) {
751 | velocityTracker = VelocityTracker.obtain();
752 | }
753 | velocityTracker.computeCurrentVelocity(1000);
754 | float translationY = containerView.getTranslationY();
755 | if (startedTracking || translationY != 0) {
756 | checkDismiss(velocityTracker.getXVelocity(), velocityTracker.getYVelocity());
757 | startedTracking = false;
758 | } else {
759 | maybeStartTracking = false;
760 | startedTracking = false;
761 | }
762 | if (velocityTracker != null) {
763 | velocityTracker.recycle();
764 | velocityTracker = null;
765 | }
766 | startedTrackingPointerId = -1;
767 | }
768 | return startedTracking || !canDismissWithSwipe();
769 | }
770 |
771 | @Override
772 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
773 | int width = MeasureSpec.getSize(widthMeasureSpec);
774 | int height = MeasureSpec.getSize(heightMeasureSpec);
775 | if (lastInsets != null && Build.VERSION.SDK_INT >= 21) {
776 | height -= lastInsets.getSystemWindowInsetBottom();
777 | }
778 |
779 | setMeasuredDimension(width, height);
780 | if (lastInsets != null && Build.VERSION.SDK_INT >= 21) {
781 | width -= lastInsets.getSystemWindowInsetRight() + lastInsets.getSystemWindowInsetLeft();
782 | }
783 | boolean isPortrait = width < height;
784 |
785 | if (containerView != null) {
786 | if (!fullWidth) {
787 | int widthSpec;
788 | widthSpec = MeasureSpec.makeMeasureSpec(isPortrait ? width + backgroundPaddingLeft * 2 : (int) Math.max(width * 0.8f, Math.min(Utils.dp(getContext(), 480), width)) + backgroundPaddingLeft * 2, MeasureSpec.EXACTLY);
789 |
790 | /*if (Utils.isTablet(getContext())) {
791 | widthSpec = MeasureSpec.makeMeasureSpec((int) (Math.min(displaySize.x, displaySize.y) * 0.8f) + backgroundPaddingLeft * 2, MeasureSpec.EXACTLY);
792 | } else {
793 | widthSpec = MeasureSpec.makeMeasureSpec(isPortrait ? width + backgroundPaddingLeft * 2 : (int) Math.max(width * 0.8f, Math.min(Utils.dp(getContext(), 480), width)) + backgroundPaddingLeft * 2, MeasureSpec.EXACTLY);
794 | }*/
795 |
796 | containerView.measure(widthSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
797 | } else {
798 | containerView.measure(MeasureSpec.makeMeasureSpec(width + backgroundPaddingLeft * 2, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
799 | }
800 | }
801 | int childCount = getChildCount();
802 | for (int i = 0; i < childCount; i++) {
803 | View child = getChildAt(i);
804 | if (child.getVisibility() == GONE || child == containerView) {
805 | continue;
806 | }
807 | if (!onCustomMeasure(child, width, height)) {
808 | measureChildWithMargins(child, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 0, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY), 0);
809 | }
810 | }
811 | }
812 |
813 | @Override
814 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
815 | layoutCount--;
816 | if (containerView != null) {
817 | if (lastInsets != null && Build.VERSION.SDK_INT >= 21) {
818 | left += lastInsets.getSystemWindowInsetLeft();
819 | right -= lastInsets.getSystemWindowInsetRight();
820 | }
821 | int t = (bottom - top) - containerView.getMeasuredHeight();
822 | int l = ((right - left) - containerView.getMeasuredWidth()) / 2;
823 | if (lastInsets != null && Build.VERSION.SDK_INT >= 21) {
824 | l += lastInsets.getSystemWindowInsetLeft();
825 | }
826 | containerView.layout(l, t, l + containerView.getMeasuredWidth(), t + containerView.getMeasuredHeight());
827 | }
828 |
829 | final int count = getChildCount();
830 | for (int i = 0; i < count; i++) {
831 | final View child = getChildAt(i);
832 | if (child.getVisibility() == GONE || child == containerView) {
833 | continue;
834 | }
835 | if (!onCustomLayout(child, left, top, right, bottom)) {
836 | final LayoutParams lp = (LayoutParams) child.getLayoutParams();
837 |
838 | final int width = child.getMeasuredWidth();
839 | final int height = child.getMeasuredHeight();
840 |
841 | int childLeft;
842 | int childTop;
843 |
844 | int gravity = lp.gravity;
845 | if (gravity == -1) {
846 | gravity = Gravity.TOP | Gravity.LEFT;
847 | }
848 |
849 | final int absoluteGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
850 | final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
851 |
852 | switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
853 | case Gravity.CENTER_HORIZONTAL:
854 | childLeft = (right - left - width) / 2 + lp.leftMargin - lp.rightMargin;
855 | break;
856 | case Gravity.RIGHT:
857 | childLeft = right - width - lp.rightMargin;
858 | break;
859 | case Gravity.LEFT:
860 | default:
861 | childLeft = lp.leftMargin;
862 | }
863 |
864 | switch (verticalGravity) {
865 | case Gravity.TOP:
866 | childTop = lp.topMargin;
867 | break;
868 | case Gravity.CENTER_VERTICAL:
869 | childTop = (bottom - top - height) / 2 + lp.topMargin - lp.bottomMargin;
870 | break;
871 | case Gravity.BOTTOM:
872 | childTop = (bottom - top) - height - lp.bottomMargin;
873 | break;
874 | default:
875 | childTop = lp.topMargin;
876 | }
877 | if (lastInsets != null && Build.VERSION.SDK_INT >= 21) {
878 | childLeft += lastInsets.getSystemWindowInsetLeft();
879 | }
880 | child.layout(childLeft, childTop, childLeft + width, childTop + height);
881 | }
882 | }
883 | if (layoutCount == 0 && startAnimationRunnable != null) {
884 | handler.removeCallbacks(startAnimationRunnable);
885 | startAnimationRunnable.run();
886 | startAnimationRunnable = null;
887 | }
888 | }
889 |
890 | @Override
891 | public boolean onInterceptTouchEvent(MotionEvent event) {
892 | if (canDismissWithSwipe()) {
893 | return onTouchEvent(event);
894 | }
895 |
896 | return super.onInterceptTouchEvent(event);
897 | }
898 |
899 | @Override
900 | public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
901 | if (maybeStartTracking && !startedTracking) {
902 | onTouchEvent(null);
903 | }
904 |
905 | super.requestDisallowInterceptTouchEvent(disallowIntercept);
906 | }
907 |
908 | @Override
909 | public boolean hasOverlappingRendering() {
910 | return false;
911 | }
912 |
913 | @Override
914 | protected void onDraw(Canvas canvas) {
915 | super.onDraw(canvas);
916 | onContainerDraw(canvas);
917 | }
918 | }
919 |
920 | private boolean onContainerTouchEvent(MotionEvent event) {
921 | return false;
922 | }
923 |
924 | private boolean canDismissWithSwipe() {
925 | return false; // todo: true
926 | }
927 |
928 | private boolean canDismissWithTouchOutside() {
929 | return true;
930 | }
931 |
932 | private void cancelSheetAnimation() {
933 | if (currentSheetAnimation != null) {
934 | currentSheetAnimation.cancel();
935 | currentSheetAnimation = null;
936 | }
937 | }
938 |
939 | private void startShowAnimation() {
940 | if (dismissed) {
941 | return;
942 | }
943 | containerView.setVisibility(View.VISIBLE);
944 | if (!onCustomOpenAnimation()) {
945 | if (Build.VERSION.SDK_INT >= 20 && useHardwareLayer) {
946 | container.setLayerType(View.LAYER_TYPE_HARDWARE, null);
947 | }
948 | containerView.setTranslationY(containerView.getMeasuredHeight());
949 | AnimatorSet animatorSet = new AnimatorSet();
950 |
951 | if (floatingActionButton != null && fabBehavior == FAB_SLIDE_UP) {
952 | animatorSet.playTogether(
953 | ObjectAnimator.ofFloat(floatingActionButton, "translationY", -(containerView.getMeasuredHeight())),
954 | ObjectAnimator.ofFloat(containerView, "translationY", 0),
955 | ObjectAnimator.ofInt(backDrawable, "alpha", dimmingValue));
956 | } else if (floatingActionButton == null || fabBehavior != FAB_SLIDE_UP) {
957 | animatorSet.playTogether(
958 | ObjectAnimator.ofFloat(containerView, "translationY", 0),
959 | ObjectAnimator.ofInt(backDrawable, "alpha", dimmingValue));
960 | }
961 |
962 | animatorSet.setDuration(200);
963 | animatorSet.setStartDelay(20);
964 | animatorSet.setInterpolator(new DecelerateInterpolator());
965 | animatorSet.addListener(new AnimatorListenerAdapter() {
966 | @Override
967 | public void onAnimationStart(Animator animation) {
968 | super.onAnimationStart(animation);
969 |
970 | if (floatingActionButton != null && fabBehavior == FAB_SHOW_HIDE) {
971 | floatingActionButton.hide();
972 | }
973 | }
974 |
975 | @Override
976 | public void onAnimationEnd(Animator animation) {
977 | if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
978 | currentSheetAnimation = null;
979 | if (useHardwareLayer) {
980 | container.setLayerType(View.LAYER_TYPE_NONE, null);
981 | }
982 | }
983 | }
984 |
985 | @Override
986 | public void onAnimationCancel(Animator animation) {
987 | if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) {
988 | currentSheetAnimation = null;
989 | }
990 | }
991 | });
992 | animatorSet.start();
993 | currentSheetAnimation = animatorSet;
994 | }
995 | }
996 |
997 | private void dismissInternal() {
998 | super.dismiss();
999 | }
1000 |
1001 | private float getPixelsInCM(float cm, boolean isX) {
1002 | return (cm / 2.54F) * (isX ? metrics.xdpi : metrics.ydpi);
1003 | }
1004 |
1005 | protected void onContainerTranslationYChanged(float translationY) {}
1006 |
1007 | public void setAllowDrawContent(boolean value) {
1008 | if (allowDrawContent != value) {
1009 | allowDrawContent = value;
1010 | container.setBackgroundDrawable(allowDrawContent ? backDrawable : null);
1011 | container.invalidate();
1012 | }
1013 | }
1014 |
1015 | protected boolean onCustomMeasure(View view, int width, int height) {
1016 | return false;
1017 | }
1018 |
1019 | protected boolean onCustomLayout(View view, int left, int top, int right, int bottom) {
1020 | return false;
1021 | }
1022 |
1023 | public void onContainerDraw(Canvas canvas) {}
1024 |
1025 | protected boolean onCustomOpenAnimation() {
1026 | return false;
1027 | }
1028 |
1029 | //--------------------------------------------------------------------------------------------------
1030 |
1031 | public static class Builder {
1032 |
1033 | private Context context;
1034 | private BottomSheet bottomSheet;
1035 |
1036 | public Builder(@NonNull Context context) {
1037 | this.context = context;
1038 | bottomSheet = new BottomSheet(context, false);
1039 | }
1040 |
1041 | public Builder(@NonNull Context context, boolean focus) {
1042 | this.context = context;
1043 | bottomSheet = new BottomSheet(context, focus);
1044 | }
1045 |
1046 | public Builder(@NonNull Context context, @BoolRes int focus) {
1047 | this.context = context;
1048 | bottomSheet = new BottomSheet(context, context.getResources().getBoolean(focus));
1049 | }
1050 |
1051 | public Builder setTitle(@StringRes int titleId) {
1052 | bottomSheet.titleText = context.getText(titleId);
1053 | return this;
1054 | }
1055 |
1056 | public Builder setTitle(@Nullable CharSequence title) {
1057 | bottomSheet.titleText = title;
1058 | return this;
1059 | }
1060 |
1061 | public Builder setItems(@ArrayRes int itemsId, final OnClickListener listener) {
1062 | bottomSheet.ITEMS.addAll(Arrays.asList(context.getResources().getTextArray(itemsId)));
1063 | bottomSheet.onClickListener = listener;
1064 | return this;
1065 | }
1066 |
1067 | public Builder setItems(@StringRes int[] items, final OnClickListener listener) {
1068 | for (int i : items) {
1069 | bottomSheet.ITEMS.add(context.getResources().getString(i));
1070 | }
1071 | bottomSheet.onClickListener = listener;
1072 | return this;
1073 | }
1074 |
1075 | public Builder setItems(CharSequence[] items, final OnClickListener listener) {
1076 | bottomSheet.ITEMS.addAll(Arrays.asList(items));
1077 | bottomSheet.onClickListener = listener;
1078 | return this;
1079 | }
1080 |
1081 | public Builder setItems(@ArrayRes int itemsId, int[] icons, final OnClickListener listener) {
1082 | bottomSheet.ITEMS.addAll(Arrays.asList(context.getResources().getTextArray(itemsId)));
1083 | for (int i: icons) {
1084 | bottomSheet.ICONS.add(ContextCompat.getDrawable(context, i));
1085 | }
1086 | bottomSheet.onClickListener = listener;
1087 | return this;
1088 | }
1089 |
1090 | public Builder setItems(@ArrayRes int itemsId, Drawable[] icons, final OnClickListener listener) {
1091 | Collections.addAll(bottomSheet.ITEMS, context.getResources().getTextArray(itemsId));
1092 | Collections.addAll(bottomSheet.ICONS, icons);
1093 | bottomSheet.onClickListener = listener;
1094 | return this;
1095 | }
1096 |
1097 | public Builder setItems(@StringRes int[] items, int[] icons, final OnClickListener listener) {
1098 | for (int i : items) {
1099 | bottomSheet.ITEMS.add(context.getResources().getString(i));
1100 | }
1101 | for (int j: icons) {
1102 | bottomSheet.ICONS.add(ContextCompat.getDrawable(context, j));
1103 | }
1104 | bottomSheet.onClickListener = listener;
1105 | return this;
1106 | }
1107 |
1108 | public Builder setItems(@StringRes int[] items, Drawable[] icons, final OnClickListener listener) {
1109 | for (int i : items) {
1110 | bottomSheet.ITEMS.add(context.getResources().getString(i));
1111 | }
1112 | Collections.addAll(bottomSheet.ICONS, icons);
1113 | bottomSheet.onClickListener = listener;
1114 | return this;
1115 | }
1116 |
1117 | public Builder setItems(@NonNull CharSequence[] items, int[] icons, final OnClickListener listener) {
1118 | bottomSheet.ITEMS.addAll(Arrays.asList(items));
1119 | for (int i: icons) {
1120 | bottomSheet.ICONS.add(ContextCompat.getDrawable(context, i));
1121 | }
1122 | bottomSheet.onClickListener = listener;
1123 | return this;
1124 | }
1125 |
1126 | public Builder setItems(@NonNull CharSequence[] items, Drawable[] icons, final OnClickListener listener) {
1127 | bottomSheet.ITEMS.addAll(Arrays.asList(items));
1128 | Collections.addAll(bottomSheet.ICONS, icons);
1129 | bottomSheet.onClickListener = listener;
1130 | return this;
1131 | }
1132 |
1133 | public Builder setMenu(@MenuRes int menuResId, final OnClickListener listener) {
1134 | BottomSheetMenu menu = new BottomSheetMenu(context);
1135 | new MenuInflater(context).inflate(menuResId, menu);
1136 |
1137 | for (int i = 0; i < menu.size(); i++) {
1138 | bottomSheet.ITEMS.add(menu.getItem(i).getTitle());
1139 | bottomSheet.ICONS.add(menu.getItem(i).getIcon());
1140 | }
1141 |
1142 | bottomSheet.onClickListener = listener;
1143 | return this;
1144 | }
1145 |
1146 | public Builder setMenu(Menu menu, final OnClickListener listener) {
1147 | for (int i = 0; i < menu.size(); i++) {
1148 | bottomSheet.ITEMS.add(menu.getItem(i).getTitle());
1149 | bottomSheet.ICONS.add(menu.getItem(i).getIcon());
1150 | }
1151 |
1152 | bottomSheet.onClickListener = listener;
1153 | return this;
1154 | }
1155 |
1156 | public Builder setView(@LayoutRes int layoutResId) {
1157 | bottomSheet.customView = LayoutInflater.from(context).inflate(layoutResId, null);
1158 | return this;
1159 | }
1160 |
1161 | public Builder setView(View view) {
1162 | bottomSheet.customView = view;
1163 | return this;
1164 | }
1165 |
1166 | //----- Styles -------------------------------------------------------------------------------------
1167 |
1168 | public Builder setContentType(@Type int type) {
1169 | bottomSheet.contentType = type;
1170 | return this;
1171 | }
1172 |
1173 | public Builder setDarkTheme(boolean theme) {
1174 | bottomSheet.darkTheme = theme;
1175 | return this;
1176 | }
1177 |
1178 | public Builder setDarkTheme(@BoolRes int theme) {
1179 | bottomSheet.darkTheme = context.getResources().getBoolean(theme);
1180 | return this;
1181 | }
1182 |
1183 | public Builder setFullWidth(boolean fullWidth) {
1184 | bottomSheet.fullWidth = fullWidth;
1185 | return this;
1186 | }
1187 |
1188 | public Builder setFullWidth(@BoolRes int fullWidth) {
1189 | bottomSheet.fullWidth = context.getResources().getBoolean(fullWidth);
1190 | return this;
1191 | }
1192 |
1193 | public Builder setCellHeight(int cellHeight) {
1194 | bottomSheet.cellHeight = cellHeight;
1195 | return this;
1196 | }
1197 |
1198 | public Builder setDividers(boolean dividers) {
1199 | bottomSheet.dividers = dividers;
1200 | return this;
1201 | }
1202 |
1203 | public Builder setDividers(@BoolRes int dividers) {
1204 | bottomSheet.dividers = context.getResources().getBoolean(dividers);
1205 | return this;
1206 | }
1207 |
1208 | public Builder setWindowDimming(@IntRange(from = 0, to = 255) int windowDimming) {
1209 | bottomSheet.dimmingValue = windowDimming;
1210 | return this;
1211 | }
1212 |
1213 | public Builder setTitleMultiline(boolean titleMultiline) {
1214 | bottomSheet.titleTextMultiline = titleMultiline;
1215 | return this;
1216 | }
1217 |
1218 | public Builder setTitleMultiline(@BoolRes int titleMultiline) {
1219 | bottomSheet.titleTextMultiline = context.getResources().getBoolean(titleMultiline);
1220 | return this;
1221 | }
1222 |
1223 | public Builder setFabBehavior(FloatingActionButton fab) {
1224 | bottomSheet.floatingActionButton = fab;
1225 | return this;
1226 | }
1227 |
1228 | public Builder setFabBehavior(FloatingActionButton fab, @FabBehavior int fabBehavior) {
1229 | bottomSheet.floatingActionButton = fab;
1230 | bottomSheet.fabBehavior = fabBehavior;
1231 | return this;
1232 | }
1233 |
1234 | //----- Colors -------------------------------------------------------------------------------------
1235 |
1236 | public Builder setBackgroundColor(@ColorInt int backgroundColor) {
1237 | bottomSheet.backgroundColor = backgroundColor;
1238 | return this;
1239 | }
1240 |
1241 | public Builder setBackgroundColorRes(@ColorRes int backgroundColorRes) {
1242 | bottomSheet.backgroundColor = ContextCompat.getColor(context, backgroundColorRes);
1243 | return this;
1244 | }
1245 |
1246 | public Builder setTitleTextColor(@ColorInt int titleTextColor) {
1247 | bottomSheet.titleTextColor = titleTextColor;
1248 | return this;
1249 | }
1250 |
1251 | public Builder setTitleTextColorRes(@ColorRes int titleTextColorRes) {
1252 | bottomSheet.titleTextColor = ContextCompat.getColor(context, titleTextColorRes);
1253 | return this;
1254 | }
1255 |
1256 | public Builder setItemTextColor(@ColorInt int itemTextColor) {
1257 | bottomSheet.itemTextColor = itemTextColor;
1258 | return this;
1259 | }
1260 |
1261 | public Builder setItemTextColorRes(@ColorRes int itemTextColorRes) {
1262 | bottomSheet.itemTextColor = ContextCompat.getColor(context, itemTextColorRes);
1263 | return this;
1264 | }
1265 |
1266 | public Builder setIconColor(@ColorInt int iconColor) {
1267 | bottomSheet.iconColor = iconColor;
1268 | return this;
1269 | }
1270 |
1271 | public Builder setIconColorRes(@ColorInt int iconColorRes) {
1272 | bottomSheet.iconColor = ContextCompat.getColor(context, iconColorRes);
1273 | return this;
1274 | }
1275 |
1276 | public Builder setItemSelector(int selector) {
1277 | bottomSheet.itemSelector = selector;
1278 | return this;
1279 | }
1280 |
1281 | //----- Interfaces ---------------------------------------------------------------------------------
1282 |
1283 | public Builder setOnShowListener(DialogInterface.OnShowListener listener) {
1284 | bottomSheet.onShowListener = listener;
1285 | return this;
1286 | }
1287 |
1288 | public Builder setOnDismissListener(DialogInterface.OnDismissListener listener) {
1289 | bottomSheet.onDismissListener = listener;
1290 | return this;
1291 | }
1292 |
1293 | public Builder setCallback(BottomSheetCallback callback) {
1294 | bottomSheet.bottomSheetCallback = callback;
1295 | return this;
1296 | }
1297 |
1298 | //----- Build --------------------------------------------------------------------------------------
1299 |
1300 | public BottomSheet show() {
1301 | bottomSheet.show();
1302 | return bottomSheet;
1303 | }
1304 |
1305 | public BottomSheet dismiss() {
1306 | bottomSheet.dismiss();
1307 | return bottomSheet;
1308 | }
1309 |
1310 | public BottomSheet create() {
1311 | return bottomSheet;
1312 | }
1313 |
1314 | //----- Getters ------------------------------------------------------------------------------------
1315 |
1316 | public TextView getTitleTextView() {
1317 | return bottomSheet.titleTextView;
1318 | }
1319 |
1320 | public ListView getListView() {
1321 | return bottomSheet.listView;
1322 | }
1323 |
1324 | public GridView getGridView() {
1325 | return bottomSheet.gridView;
1326 | }
1327 |
1328 | public View getView() {
1329 | return bottomSheet.customView;
1330 | }
1331 |
1332 | //----- Deprecated ---------------------------------------------------------------------------------
1333 |
1334 | @Deprecated
1335 | public Builder setCustomView(View view) {
1336 | bottomSheet.customView = view;
1337 | return this;
1338 | }
1339 |
1340 | @Deprecated
1341 | public Builder setCustomView(@LayoutRes int layoutResId) {
1342 | bottomSheet.customView = LayoutInflater.from(context).inflate(layoutResId, null);
1343 | return this;
1344 | }
1345 | }
1346 |
1347 | //--------------------------------------------------------------------------------------------------
1348 |
1349 | private class BottomSheetAdapter extends BaseAdapter {
1350 |
1351 | @Override
1352 | public int getCount() {
1353 | return ITEMS != null ? ITEMS.size() : 0;
1354 | }
1355 |
1356 | @Override
1357 | public Object getItem(int i) {
1358 | return null;
1359 | }
1360 |
1361 | @Override
1362 | public long getItemId(int i) {
1363 | return 0;
1364 | }
1365 |
1366 | @Override
1367 | public View getView(int position, View view, ViewGroup viewGroup) {
1368 | int type = getItemViewType(position);
1369 | BottomSheetItem item = bottomsheetItems.get(position);
1370 |
1371 | if (type == 0) {
1372 | if (contentType == LIST) {
1373 | if (view == null) {
1374 | view = new BottomSheetCell(getContext());
1375 | }
1376 |
1377 | BottomSheetCell cell = (BottomSheetCell) view;
1378 | cell.setIcon(item.icon, iconColor);
1379 | cell.setText(item.text, itemTextColor);
1380 | cell.setHeight(cellHeight);
1381 | if (position != bottomsheetItems.size() - 1) {
1382 | cell.setDivider(dividers);
1383 | cell.setDividerColor(darkTheme);
1384 | }
1385 | } else {
1386 | if (view == null) {
1387 | view = new BottomSheetGrid(getContext());
1388 | }
1389 |
1390 | BottomSheetGrid cell = (BottomSheetGrid) view;
1391 | cell.setIcon(item.icon, iconColor);
1392 | cell.setText(item.text, itemTextColor);
1393 | }
1394 | }
1395 |
1396 | return view;
1397 | }
1398 |
1399 | @Override
1400 | public int getItemViewType(int i) {
1401 | return 0;
1402 | }
1403 |
1404 | @Override
1405 | public int getViewTypeCount() {
1406 | return 1;
1407 | }
1408 | }
1409 | }
--------------------------------------------------------------------------------
/bottomsheet/src/main/java/org/michaelbel/bottomsheet/BottomSheetCallback.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Michael Bely
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 org.michaelbel.bottomsheet;
18 |
19 | /**
20 | * Date: 17 FEB 2018
21 | * Time: 22:52 MSK
22 | *
23 | * @author Michael Bel
24 | */
25 |
26 | public interface BottomSheetCallback {
27 |
28 | void onShown();
29 |
30 | void onDismissed();
31 | }
--------------------------------------------------------------------------------
/bottomsheet/src/main/java/org/michaelbel/bottomsheet/BottomSheetCell.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Michael Bely
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 org.michaelbel.bottomsheet;
18 |
19 | import android.content.Context;
20 | import android.graphics.Canvas;
21 | import android.graphics.Paint;
22 | import android.graphics.PorterDuff;
23 | import android.graphics.drawable.Drawable;
24 | import android.support.annotation.ColorInt;
25 | import android.support.annotation.DrawableRes;
26 | import android.support.annotation.NonNull;
27 | import android.support.v4.content.ContextCompat;
28 | import android.text.TextUtils;
29 | import android.util.TypedValue;
30 | import android.view.Gravity;
31 | import android.view.ViewGroup;
32 | import android.widget.FrameLayout;
33 | import android.widget.ImageView;
34 | import android.widget.TextView;
35 |
36 | /**
37 | * Date: 17 FEB 2018
38 | * Time: 00:30 MSK
39 | *
40 | * @author Michael Bel
41 | */
42 |
43 | @SuppressWarnings("all")
44 | public class BottomSheetCell extends FrameLayout {
45 |
46 | private Paint paint;
47 | private int cellHeight;
48 | private boolean divider;
49 |
50 | private TextView textView;
51 | private ImageView iconView;
52 |
53 | public BottomSheetCell(Context context) {
54 | super(context);
55 |
56 | if (paint == null) {
57 | paint = new Paint();
58 | paint.setStrokeWidth(1);
59 | paint.setColor(0x1F000000);
60 | }
61 |
62 | cellHeight = Utils.dp(context, 48);
63 |
64 | iconView = new ImageView(context);
65 | iconView.setScaleType(ImageView.ScaleType.CENTER);
66 |
67 | LayoutParams params1 = new LayoutParams(Utils.dp(context, 24), Utils.dp(context, 24));
68 | params1.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
69 | params1.leftMargin = Utils.dp(context, 16);
70 | params1.rightMargin = Utils.dp(context, 16);
71 |
72 | iconView.setLayoutParams(params1);
73 | addView(iconView);
74 |
75 | textView = new TextView(context);
76 | textView.setLines(1);
77 | textView.setMaxLines(1);
78 | textView.setSingleLine(true);
79 | textView.setEllipsize(TextUtils.TruncateAt.END);
80 | textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
81 |
82 | LayoutParams params2 = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
83 | params2.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
84 | params2.leftMargin = Utils.dp(context, 16);
85 | params2.rightMargin = Utils.dp(context, 16);
86 |
87 | textView.setLayoutParams(params2);
88 | addView(textView);
89 | }
90 |
91 | public BottomSheetCell setIcon(@DrawableRes int resId, @ColorInt int color) {
92 | if (resId != 0) {
93 | Drawable res = ContextCompat.getDrawable(getContext(), resId);
94 | if (res != null) {
95 | res.clearColorFilter();
96 | res.mutate().setColorFilter(color, PorterDuff.Mode.MULTIPLY);
97 | }
98 |
99 | iconView.setImageDrawable(res);
100 |
101 | LayoutParams params2 = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
102 | params2.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
103 | params2.leftMargin = Utils.dp(getContext(), 72);
104 | params2.rightMargin = Utils.dp(getContext(), 16);
105 | textView.setLayoutParams(params2);
106 | } else {
107 | LayoutParams params2 = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
108 | params2.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
109 | params2.leftMargin = Utils.dp(getContext(), 16);
110 | params2.rightMargin = Utils.dp(getContext(), 16);
111 | textView.setLayoutParams(params2);
112 | }
113 |
114 | return this;
115 | }
116 |
117 | public BottomSheetCell setIcon(Drawable resId, @ColorInt int color) {
118 | if (resId != null) {
119 | Drawable res = resId;
120 | if (res != null) {
121 | res.clearColorFilter();
122 | res.mutate().setColorFilter(color, PorterDuff.Mode.MULTIPLY);
123 | }
124 |
125 | iconView.setImageDrawable(res);
126 |
127 | LayoutParams params2 = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
128 | params2.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
129 | params2.leftMargin = Utils.dp(getContext(), 72);
130 | params2.rightMargin = Utils.dp(getContext(), 16);
131 | textView.setLayoutParams(params2);
132 | } else {
133 | LayoutParams params2 = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
134 | params2.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
135 | params2.leftMargin = Utils.dp(getContext(), 16);
136 | params2.rightMargin = Utils.dp(getContext(), 16);
137 | textView.setLayoutParams(params2);
138 | }
139 |
140 | return this;
141 | }
142 |
143 | public BottomSheetCell setText(@NonNull CharSequence text, @ColorInt int color) {
144 | textView.setText(text);
145 | textView.setTextColor(color);
146 | return this;
147 | }
148 |
149 | public BottomSheetCell setHeight(int height) {
150 | cellHeight = height;
151 | return this;
152 | }
153 |
154 | public BottomSheetCell setDivider(boolean divider) {
155 | this.divider = divider;
156 | setWillNotDraw(!divider);
157 | return this;
158 | }
159 |
160 | public BottomSheetCell setDividerColor(boolean theme) {
161 | paint.setColor(!theme ? 0x1F000000 : 0x1FFFFFFF);
162 | setWillNotDraw(false);
163 | return this;
164 | }
165 |
166 | @Override
167 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
168 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
169 | int width = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.EXACTLY);
170 | int height = cellHeight + (divider ? 1 : 0);
171 | setMeasuredDimension(width, height);
172 | }
173 |
174 | @Override
175 | protected void onDraw(Canvas canvas) {
176 | if (divider) {
177 | canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint);
178 | }
179 | }
180 | }
--------------------------------------------------------------------------------
/bottomsheet/src/main/java/org/michaelbel/bottomsheet/BottomSheetGrid.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Michael Bely
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 org.michaelbel.bottomsheet;
18 |
19 | import android.content.Context;
20 | import android.graphics.PorterDuff;
21 | import android.graphics.drawable.Drawable;
22 | import android.support.annotation.ColorInt;
23 | import android.support.annotation.DrawableRes;
24 | import android.support.annotation.NonNull;
25 | import android.support.v4.content.ContextCompat;
26 | import android.text.TextUtils;
27 | import android.util.TypedValue;
28 | import android.view.Gravity;
29 | import android.view.ViewGroup;
30 | import android.widget.ImageView;
31 | import android.widget.LinearLayout;
32 | import android.widget.TextView;
33 |
34 | /**
35 | * Date: 17 FEB 2018
36 | * Time: 00:31 MSK
37 | *
38 | * @author Michael Bel
39 | */
40 |
41 | @SuppressWarnings("all")
42 | public class BottomSheetGrid extends LinearLayout {
43 |
44 | private TextView textView;
45 | private ImageView iconView;
46 |
47 | public BottomSheetGrid(Context context) {
48 | super(context);
49 |
50 | setOrientation(VERTICAL);
51 | setPadding(Utils.dp(getContext(), 24), Utils.dp(getContext(), 16), Utils.dp(getContext(), 24), Utils.dp(getContext(), 16));
52 |
53 | iconView = new ImageView(context);
54 | iconView.setScaleType(ImageView.ScaleType.CENTER);
55 |
56 | LayoutParams params1 = new LayoutParams(Utils.dp(getContext(), 48), Utils.dp(getContext(), 48));
57 | params1.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
58 |
59 | iconView.setLayoutParams(params1);
60 | addView(iconView);
61 |
62 | textView = new TextView(context);
63 | textView.setLines(1);
64 | textView.setMaxLines(1);
65 | textView.setSingleLine(true);
66 | textView.setEllipsize(TextUtils.TruncateAt.END);
67 | textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
68 |
69 | LayoutParams params2 = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
70 | params2.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
71 |
72 | textView.setLayoutParams(params2);
73 | addView(textView);
74 | }
75 |
76 | public BottomSheetGrid setIcon(@DrawableRes int resId, @ColorInt int color) {
77 | Drawable icon = ContextCompat.getDrawable(getContext(), resId);
78 | if (icon != null) {
79 | icon.clearColorFilter();
80 | icon.mutate().setColorFilter(color, PorterDuff.Mode.MULTIPLY);
81 | }
82 |
83 | iconView.setImageDrawable(icon);
84 | return this;
85 | }
86 |
87 | public BottomSheetGrid setIcon(Drawable resId, @ColorInt int color) {
88 | Drawable icon = resId;
89 | if (icon != null) {
90 | icon.clearColorFilter();
91 | icon.mutate().setColorFilter(color, PorterDuff.Mode.MULTIPLY);
92 | }
93 |
94 | iconView.setImageDrawable(icon);
95 | return this;
96 | }
97 |
98 | public BottomSheetGrid setText(@NonNull CharSequence text, @ColorInt int color) {
99 | textView.setText(text);
100 | textView.setTextColor(color);
101 | return this;
102 | }
103 | }
--------------------------------------------------------------------------------
/bottomsheet/src/main/java/org/michaelbel/bottomsheet/BottomSheetItem.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Michael Bely
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 org.michaelbel.bottomsheet;
18 |
19 | import android.graphics.drawable.Drawable;
20 |
21 | /**
22 | * Date: 3 MAR 2018
23 | * Time: 13:58 MSK
24 | *
25 | * @author Michael Bel
26 | */
27 |
28 | @SuppressWarnings("all")
29 | public class BottomSheetItem {
30 |
31 | public Drawable icon;
32 | public CharSequence text;
33 |
34 | public BottomSheetItem() {}
35 |
36 | public BottomSheetItem(CharSequence text, Drawable icon) {
37 | this.text = text;
38 | this.icon = icon;
39 | }
40 | }
--------------------------------------------------------------------------------
/bottomsheet/src/main/java/org/michaelbel/bottomsheet/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Michael Bely
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 org.michaelbel.bottomsheet;
18 |
19 | import android.content.Context;
20 | import android.support.annotation.NonNull;
21 |
22 | import org.michaelbel.bottomsheetdialog.R;
23 |
24 | /**
25 | * Date: 17 FEB 2018
26 | * Time: 00:32 MSK
27 | *
28 | * @author Michael Bel
29 | */
30 |
31 | @SuppressWarnings("all")
32 | public class Utils {
33 |
34 | public static int dp(@NonNull Context context, float value) {
35 | return (int) Math.ceil(context.getResources().getDisplayMetrics().density * value);
36 | }
37 |
38 | public static boolean isTablet(@NonNull Context context) {
39 | return context.getResources().getBoolean(R.bool.tablet);
40 | }
41 | }
--------------------------------------------------------------------------------
/bottomsheet/src/main/java/org/michaelbel/bottomsheet/annotation/Beta.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Michael Bely
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 org.michaelbel.bottomsheet.annotation;
18 |
19 | import java.lang.annotation.Documented;
20 | import java.lang.annotation.ElementType;
21 | import java.lang.annotation.Retention;
22 | import java.lang.annotation.RetentionPolicy;
23 | import java.lang.annotation.Target;
24 |
25 | /**
26 | * Date: 3 MAR 2018
27 | * Time: 20:14 MSK
28 | *
29 | * @author Michael Bel
30 | */
31 |
32 | @Retention(RetentionPolicy.SOURCE)
33 | @Target({
34 | ElementType.ANNOTATION_TYPE,
35 | ElementType.CONSTRUCTOR,
36 | ElementType.FIELD,
37 | ElementType.METHOD,
38 | ElementType.TYPE })
39 | @Documented
40 | @SuppressWarnings("all")
41 | public @interface Beta {}
--------------------------------------------------------------------------------
/bottomsheet/src/main/java/org/michaelbel/bottomsheet/annotation/New.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Michael Bely
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 org.michaelbel.bottomsheet.annotation;
18 |
19 | import java.lang.annotation.Documented;
20 | import java.lang.annotation.ElementType;
21 | import java.lang.annotation.Retention;
22 | import java.lang.annotation.RetentionPolicy;
23 | import java.lang.annotation.Target;
24 |
25 | /**
26 | * Date: 3 MAR 2018
27 | * Time: 20:09 MSK
28 | *
29 | * @author Michael Bel
30 | */
31 |
32 | @Retention(RetentionPolicy.SOURCE)
33 | @Target({
34 | ElementType.ANNOTATION_TYPE,
35 | ElementType.CONSTRUCTOR,
36 | ElementType.FIELD,
37 | ElementType.METHOD,
38 | ElementType.TYPE })
39 | @Documented
40 | @SuppressWarnings("all")
41 | public @interface New {
42 | String version();
43 | }
--------------------------------------------------------------------------------
/bottomsheet/src/main/java/org/michaelbel/bottomsheet/menu/BottomSheetMenu.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Michael Bely
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 org.michaelbel.bottomsheet.menu;
18 |
19 | import android.content.ComponentName;
20 | import android.content.Context;
21 | import android.content.Intent;
22 | import android.content.pm.PackageManager;
23 | import android.content.pm.ResolveInfo;
24 | import android.view.KeyEvent;
25 | import android.view.Menu;
26 | import android.view.MenuItem;
27 | import android.view.SubMenu;
28 |
29 | import java.util.ArrayList;
30 | import java.util.List;
31 |
32 | /**
33 | * Date: 3 MAR 2018
34 | * Time: 14:03 MSK
35 | *
36 | * @author Michael Bel
37 | */
38 |
39 | @SuppressWarnings("all")
40 | public class BottomSheetMenu implements Menu {
41 |
42 | private Context mContext;
43 |
44 | private boolean mIsQwerty;
45 |
46 | private ArrayList mItems;
47 |
48 | public BottomSheetMenu(Context context) {
49 | mContext = context;
50 | mItems = new ArrayList<>();
51 | }
52 |
53 | public Context getContext() {
54 | return mContext;
55 | }
56 |
57 | public MenuItem add(CharSequence title) {
58 | return add(0, 0, 0, title);
59 | }
60 |
61 | public MenuItem add(int titleRes) {
62 | return add(0, 0, 0, titleRes);
63 | }
64 |
65 | public MenuItem add(int groupId, int itemId, int order, int titleRes) {
66 | return add(groupId, itemId, order, mContext.getResources().getString(titleRes));
67 | }
68 |
69 | public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
70 | BottomSheetMenuItem item = new BottomSheetMenuItem(getContext(), groupId, itemId, 0, order, title);
71 | mItems.add(item);
72 | return item;
73 | }
74 |
75 | public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
76 | PackageManager pm = mContext.getPackageManager();
77 | final List lri = pm.queryIntentActivityOptions(caller, specifics, intent, 0);
78 | final int N = lri != null ? lri.size() : 0;
79 |
80 | if ((flags & FLAG_APPEND_TO_GROUP) == 0) {
81 | removeGroup(groupId);
82 | }
83 |
84 | for (int i = 0; i < N; i++) {
85 | final ResolveInfo ri = lri.get(i);
86 | Intent rintent = new Intent(ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]);
87 | rintent.setComponent(new ComponentName(ri.activityInfo.applicationInfo.packageName, ri.activityInfo.name));
88 | final MenuItem item = add(groupId, itemId, order, ri.loadLabel(pm)).setIcon(ri.loadIcon(pm)).setIntent(rintent);
89 |
90 | if (outSpecificItems != null && ri.specificIndex >= 0) {
91 | outSpecificItems[ri.specificIndex] = item;
92 | }
93 | }
94 |
95 | return N;
96 | }
97 |
98 | public SubMenu addSubMenu(CharSequence title) {
99 | return null;
100 | }
101 |
102 | public SubMenu addSubMenu(int titleRes) {
103 | return null;
104 | }
105 |
106 | public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
107 | return null;
108 | }
109 |
110 | public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
111 | return null;
112 | }
113 |
114 | public void clear() {
115 | mItems.clear();
116 | }
117 |
118 | public void close() {
119 | }
120 |
121 | private int findItemIndex(int id) {
122 | final ArrayList items = mItems;
123 | final int itemCount = items.size();
124 | for (int i = 0; i < itemCount; i++) {
125 | if (items.get(i).getItemId() == id) {
126 | return i;
127 | }
128 | }
129 |
130 | return -1;
131 | }
132 |
133 | public MenuItem findItem(int id) {
134 | return mItems.get(findItemIndex(id));
135 | }
136 |
137 | public MenuItem getItem(int index) {
138 | return mItems.get(index);
139 | }
140 |
141 | public boolean hasVisibleItems() {
142 | final ArrayList items = mItems;
143 | final int itemCount = items.size();
144 |
145 | for (int i = 0; i < itemCount; i++) {
146 | if (items.get(i).isVisible()) {
147 | return true;
148 | }
149 | }
150 |
151 | return false;
152 | }
153 |
154 | private BottomSheetMenuItem findItemWithShortcut(int keyCode, KeyEvent event) {
155 | final boolean qwerty = mIsQwerty;
156 | final ArrayList items = mItems;
157 | final int itemCount = items.size();
158 |
159 | for (int i = 0; i < itemCount; i++) {
160 | BottomSheetMenuItem item = items.get(i);
161 | final char shortcut = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut();
162 | if (keyCode == shortcut) {
163 | return item;
164 | }
165 | }
166 |
167 | return null;
168 | }
169 |
170 | public boolean isShortcutKey(int keyCode, KeyEvent event) {
171 | return findItemWithShortcut(keyCode, event) != null;
172 | }
173 |
174 | public boolean performIdentifierAction(int id, int flags) {
175 | final int index = findItemIndex(id);
176 | if (index < 0) {
177 | return false;
178 | }
179 |
180 | return mItems.get(index).invoke();
181 | }
182 |
183 | public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
184 | BottomSheetMenuItem item = findItemWithShortcut(keyCode, event);
185 | if (item == null) {
186 | return false;
187 | }
188 |
189 | return item.invoke();
190 | }
191 |
192 | public void removeGroup(int groupId) {
193 | final ArrayList items = mItems;
194 | int itemCount = items.size();
195 | int i = 0;
196 | while (i < itemCount) {
197 | if (items.get(i).getGroupId() == groupId) {
198 | items.remove(i);
199 | itemCount--;
200 | } else {
201 | i++;
202 | }
203 | }
204 | }
205 |
206 | public void removeItem(int id) {
207 | mItems.remove(findItemIndex(id));
208 | }
209 |
210 | public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
211 | final ArrayList items = mItems;
212 | final int itemCount = items.size();
213 |
214 | for (int i = 0; i < itemCount; i++) {
215 | BottomSheetMenuItem item = items.get(i);
216 | if (item.getGroupId() == group) {
217 | item.setCheckable(checkable);
218 | item.setExclusiveCheckable(exclusive);
219 | }
220 | }
221 | }
222 |
223 | public void setGroupEnabled(int group, boolean enabled) {
224 | final ArrayList items = mItems;
225 | final int itemCount = items.size();
226 |
227 | for (int i = 0; i < itemCount; i++) {
228 | BottomSheetMenuItem item = items.get(i);
229 | if (item.getGroupId() == group) {
230 | item.setEnabled(enabled);
231 | }
232 | }
233 | }
234 |
235 | public void setGroupVisible(int group, boolean visible) {
236 | final ArrayList items = mItems;
237 | final int itemCount = items.size();
238 |
239 | for (int i = 0; i < itemCount; i++) {
240 | BottomSheetMenuItem item = items.get(i);
241 | if (item.getGroupId() == group) {
242 | item.setVisible(visible);
243 | }
244 | }
245 | }
246 |
247 | public void setQwertyMode(boolean isQwerty) {
248 | mIsQwerty = isQwerty;
249 | }
250 |
251 | public int size() {
252 | return mItems.size();
253 | }
254 | }
--------------------------------------------------------------------------------
/bottomsheet/src/main/java/org/michaelbel/bottomsheet/menu/BottomSheetMenuItem.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Michael Bely
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 org.michaelbel.bottomsheet.menu;
18 |
19 | import android.content.Context;
20 | import android.content.Intent;
21 | import android.graphics.drawable.Drawable;
22 | import android.support.annotation.DrawableRes;
23 | import android.view.ActionProvider;
24 | import android.view.ContextMenu.ContextMenuInfo;
25 | import android.view.MenuItem;
26 | import android.view.SubMenu;
27 | import android.view.View;
28 |
29 | /**
30 | * Date: 3 MAR 2018
31 | * Time: 14:04 MSK
32 | *
33 | * @author Michael Bel
34 | */
35 |
36 | @SuppressWarnings("all")
37 | public class BottomSheetMenuItem implements MenuItem {
38 |
39 | private static final int CHECKABLE = 0x00000001;
40 | private static final int CHECKED = 0x00000002;
41 | private static final int EXCLUSIVE = 0x00000004;
42 | private static final int HIDDEN = 0x00000008;
43 | private static final int ENABLED = 0x00000010;
44 |
45 | private final int mId;
46 | private final int mGroup;
47 | private final int mOrdering;
48 | private final int mCategoryOrder;
49 |
50 | private Intent mIntent;
51 | private Context mContext;
52 |
53 | private CharSequence mTitle;
54 | private CharSequence mTitleCondensed;
55 |
56 | private char mShortcutNumericChar;
57 | private char mShortcutAlphabeticChar;
58 |
59 | private Drawable mIconDrawable;
60 |
61 | private int mIconResId = NO_ICON;
62 |
63 | private OnMenuItemClickListener mClickListener;
64 |
65 | private static final int NO_ICON = 0;
66 |
67 | private int mFlags = ENABLED;
68 |
69 | /**
70 | * Creates a MenuItem
71 | *
72 | * @param context Context of the MenuItem
73 | * @param group Group id of the MenuItem
74 | * @param id Id of the MenuItem
75 | * @param categoryOrder Category order of the MenuItem
76 | * @param ordering Ordering of the MenuItem
77 | * @param title Title of the MenuItem
78 | */
79 | public BottomSheetMenuItem(Context context, int group, int id, int categoryOrder, int ordering, CharSequence title) {
80 | mContext = context;
81 | mId = id;
82 | mGroup = group;
83 | mCategoryOrder = categoryOrder;
84 | mOrdering = ordering;
85 | mTitle = title;
86 | }
87 |
88 | /**
89 | * Creates a MenuItem
90 | *
91 | * @param context Context of the MenuItem
92 | * @param title Title of the MenuItem
93 | * @param icon Drawable resource of the MenuItem
94 | */
95 | public BottomSheetMenuItem(Context context, CharSequence title, @DrawableRes int icon) {
96 | this(context, 0, 0, 0, 0, title);
97 | setIcon(icon);
98 | }
99 |
100 | /**
101 | * Creates a MenuItem
102 | *
103 | * @param context Context of the MenuItem
104 | * @param title Title of the MenuItem
105 | * @param icon Drawable of the MenuItem
106 | */
107 | public BottomSheetMenuItem(Context context, CharSequence title, Drawable icon) {
108 | this(context, 0, 0, 0, 0, title);
109 | setIcon(icon);
110 | }
111 |
112 | /**
113 | * Creates a MenuItem
114 | *
115 | * @param context Context of the MenuItem
116 | * @param id Id of the MenuItem
117 | * @param title Title of the MenuItem
118 | * @param icon Drawable resource of the MenuItem
119 | */
120 | public BottomSheetMenuItem(Context context, int id, CharSequence title, @DrawableRes int icon) {
121 | this(context, 0, id, 0, 0, title);
122 | setIcon(icon);
123 | }
124 |
125 | /**
126 | * Creates a MenuItem
127 | *
128 | * @param context Context of the MenuItem
129 | * @param id Id of the MenuItem
130 | * @param title Title of the MenuItem
131 | * @param icon Drawable of the MenuItem
132 | */
133 | public BottomSheetMenuItem(Context context, int id, CharSequence title, Drawable icon) {
134 | this(context, 0, id, 0, 0, title);
135 | setIcon(icon);
136 | }
137 |
138 | public char getAlphabeticShortcut() {
139 | return mShortcutAlphabeticChar;
140 | }
141 |
142 | public int getGroupId() {
143 | return mGroup;
144 | }
145 |
146 | public Drawable getIcon() {
147 | return mIconDrawable;
148 | }
149 |
150 | public Intent getIntent() {
151 | return mIntent;
152 | }
153 |
154 | public int getItemId() {
155 | return mId;
156 | }
157 |
158 | public ContextMenuInfo getMenuInfo() {
159 | return null;
160 | }
161 |
162 | public char getNumericShortcut() {
163 | return mShortcutNumericChar;
164 | }
165 |
166 | public int getOrder() {
167 | return mOrdering;
168 | }
169 |
170 | public SubMenu getSubMenu() {
171 | return null;
172 | }
173 |
174 | public CharSequence getTitle() {
175 | return mTitle;
176 | }
177 |
178 | public CharSequence getTitleCondensed() {
179 | return mTitleCondensed != null ? mTitleCondensed : mTitle;
180 | }
181 |
182 | public boolean hasSubMenu() {
183 | return false;
184 | }
185 |
186 | public boolean isCheckable() {
187 | return (mFlags & CHECKABLE) != 0;
188 | }
189 |
190 | public boolean isChecked() {
191 | return (mFlags & CHECKED) != 0;
192 | }
193 |
194 | public boolean isEnabled() {
195 | return (mFlags & ENABLED) != 0;
196 | }
197 |
198 | public boolean isVisible() {
199 | return (mFlags & HIDDEN) == 0;
200 | }
201 |
202 | public MenuItem setAlphabeticShortcut(char alphaChar) {
203 | mShortcutAlphabeticChar = alphaChar;
204 | return this;
205 | }
206 |
207 | public MenuItem setCheckable(boolean checkable) {
208 | mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
209 | return this;
210 | }
211 |
212 | public BottomSheetMenuItem setExclusiveCheckable(boolean exclusive) {
213 | mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
214 | return this;
215 | }
216 |
217 | public MenuItem setChecked(boolean checked) {
218 | mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
219 | return this;
220 | }
221 |
222 | public MenuItem setEnabled(boolean enabled) {
223 | mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0);
224 | return this;
225 | }
226 |
227 | public MenuItem setIcon(Drawable icon) {
228 | mIconDrawable = icon;
229 | mIconResId = NO_ICON;
230 | return this;
231 | }
232 |
233 | public MenuItem setIcon(int iconRes) {
234 | if (iconRes != NO_ICON) {
235 | mIconResId = iconRes;
236 | mIconDrawable = mContext.getResources().getDrawable(iconRes);
237 | }
238 |
239 | return this;
240 | }
241 |
242 | public MenuItem setIntent(Intent intent) {
243 | mIntent = intent;
244 | return this;
245 | }
246 |
247 | public MenuItem setNumericShortcut(char numericChar) {
248 | mShortcutNumericChar = numericChar;
249 | return this;
250 | }
251 |
252 | public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
253 | mClickListener = menuItemClickListener;
254 | return this;
255 | }
256 |
257 | public MenuItem setShortcut(char numericChar, char alphaChar) {
258 | mShortcutNumericChar = numericChar;
259 | mShortcutAlphabeticChar = alphaChar;
260 | return this;
261 | }
262 |
263 | public MenuItem setTitle(CharSequence title) {
264 | mTitle = title;
265 | return this;
266 | }
267 |
268 | public MenuItem setTitle(int title) {
269 | mTitle = mContext.getResources().getString(title);
270 | return this;
271 | }
272 |
273 | public MenuItem setTitleCondensed(CharSequence title) {
274 | mTitleCondensed = title;
275 | return this;
276 | }
277 |
278 | public MenuItem setVisible(boolean visible) {
279 | mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN);
280 | return this;
281 | }
282 |
283 | public boolean invoke() {
284 | if (mClickListener != null && mClickListener.onMenuItemClick(this)) {
285 | return true;
286 | }
287 |
288 | if (mIntent != null) {
289 | mContext.startActivity(mIntent);
290 | return true;
291 | }
292 |
293 | return false;
294 | }
295 |
296 | public void setShowAsAction(int show) {
297 | // Do nothing. ActionMenuItems always show as action buttons.
298 | }
299 |
300 | public MenuItem setActionView(View actionView) {
301 | throw new UnsupportedOperationException();
302 | }
303 |
304 | public View getActionView() {
305 | return null;
306 | }
307 |
308 | @Override
309 | public MenuItem setActionView(int resId) {
310 | throw new UnsupportedOperationException();
311 | }
312 |
313 | @Override
314 | public ActionProvider getActionProvider() {
315 | return null;
316 | }
317 |
318 | @Override
319 | public MenuItem setActionProvider(ActionProvider actionProvider) {
320 | throw new UnsupportedOperationException();
321 | }
322 |
323 | @Override
324 | public MenuItem setShowAsActionFlags(int actionEnum) {
325 | setShowAsAction(actionEnum);
326 | return this;
327 | }
328 |
329 | @Override
330 | public boolean expandActionView() {
331 | return false;
332 | }
333 |
334 | @Override
335 | public boolean collapseActionView() {
336 | return false;
337 | }
338 |
339 | @Override
340 | public boolean isActionViewExpanded() {
341 | return false;
342 | }
343 |
344 | @Override
345 | public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
346 | // No need to save the listener; ActionMenuItem does not support collapsing items.
347 | return this;
348 | }
349 | }
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/anim/no_animation.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/drawable-hdpi/sheet_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/bottomsheet/src/main/res/drawable-hdpi/sheet_shadow.9.png
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/drawable-mdpi/sheet_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/bottomsheet/src/main/res/drawable-mdpi/sheet_shadow.9.png
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/drawable-v21/selectable_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/drawable-v21/selectable_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/drawable-xhdpi/sheet_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/bottomsheet/src/main/res/drawable-xhdpi/sheet_shadow.9.png
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/drawable-xxhdpi/sheet_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/bottomsheet/src/main/res/drawable-xxhdpi/sheet_shadow.9.png
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/drawable-xxxhdpi/sheet_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/bottomsheet/src/main/res/drawable-xxxhdpi/sheet_shadow.9.png
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/drawable/selectable_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/drawable/selectable_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/drawable/transparent.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/values-sw600dp/values.xml:
--------------------------------------------------------------------------------
1 |
2 | true
3 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/values-sw720dp/values.xml:
--------------------------------------------------------------------------------
1 |
2 | true
3 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
19 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
--------------------------------------------------------------------------------
/bottomsheet/src/main/res/values/values.xml:
--------------------------------------------------------------------------------
1 |
2 | false
3 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | jcenter()
4 | google()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.2.1'
9 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | jcenter()
17 | google()
18 | }
19 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Sep 27 01:56:23 MSK 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/screenshots/bs_dark_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/bs_dark_1.png
--------------------------------------------------------------------------------
/screenshots/bs_dark_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/bs_dark_2.png
--------------------------------------------------------------------------------
/screenshots/bs_dark_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/bs_dark_3.png
--------------------------------------------------------------------------------
/screenshots/bs_dark_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/bs_dark_4.png
--------------------------------------------------------------------------------
/screenshots/bs_dark_landscape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/bs_dark_landscape.png
--------------------------------------------------------------------------------
/screenshots/bs_light_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/bs_light_1.png
--------------------------------------------------------------------------------
/screenshots/bs_light_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/bs_light_2.png
--------------------------------------------------------------------------------
/screenshots/bs_light_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/bs_light_3.png
--------------------------------------------------------------------------------
/screenshots/bs_light_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/bs_light_4.png
--------------------------------------------------------------------------------
/screenshots/bs_light_landscape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/bs_light_landscape.png
--------------------------------------------------------------------------------
/screenshots/demo-gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/demo-gif.gif
--------------------------------------------------------------------------------
/screenshots/direct-apk-download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/direct-apk-download.png
--------------------------------------------------------------------------------
/screenshots/web1024x500.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/web1024x500.png
--------------------------------------------------------------------------------
/screenshots/web512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/web512x512.png
--------------------------------------------------------------------------------
/screenshots/wiki_bs_dividers_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/wiki_bs_dividers_1.jpg
--------------------------------------------------------------------------------
/screenshots/wiki_bs_dividers_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/wiki_bs_dividers_2.jpg
--------------------------------------------------------------------------------
/screenshots/wiki_bs_fullwidth_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/wiki_bs_fullwidth_1.jpg
--------------------------------------------------------------------------------
/screenshots/wiki_bs_fullwidth_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbel/BottomSheet/b32cd0e67419ff28604ed13193ecf49840e53565/screenshots/wiki_bs_fullwidth_2.jpg
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':bottomsheet'
2 |
--------------------------------------------------------------------------------