├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md ├── pull_request_template.md └── workflows │ └── android.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── README_OLD.md ├── RELEASE_NOTES.md ├── art ├── basic.png ├── basic_list.png ├── basic_with_buttons.png ├── bottomsheet_customview.png ├── bottomsheet_peekheight.gif ├── checkbox_prompt.png ├── color_chooser.png ├── color_chooser_sub.png ├── custom_argb.png ├── custom_view.png ├── customtheme.png ├── datepicker.png ├── datetimepicker.png ├── file_chooser.png ├── file_emptytext.png ├── file_folder_creation.png ├── icon.png ├── input.png ├── input_max_length.png ├── lightanddarkthemes.png ├── multi_choice_list.png ├── showcase4.png ├── single_choice_list.png ├── stacked_buttons.png └── timepicker.png ├── bottomsheets ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── afollestad │ │ └── materialdialogs │ │ └── bottomsheets │ │ ├── BottomSheet.kt │ │ ├── BottomSheets.kt │ │ ├── GridIconDialogAdapter.kt │ │ ├── GridItem.kt │ │ ├── HeightMatchesWidthImageView.kt │ │ └── Util.kt │ ├── res-public │ └── values │ │ └── integers.xml │ └── res │ ├── layout │ ├── md_dialog_base_bottomsheet.xml │ ├── md_dialog_base_no_buttons.xml │ └── md_griditem.xml │ ├── values-land │ └── integers.xml │ ├── values-large-land │ └── integers.xml │ ├── values-large │ └── integers.xml │ ├── values-v21 │ └── styles.xml │ └── values │ ├── integers.xml │ └── styles.xml ├── build.gradle ├── color ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── afollestad │ │ └── materialdialogs │ │ └── color │ │ ├── ColorGridAdapter.kt │ │ ├── ColorPagerAdapter.kt │ │ ├── ColorPalette.kt │ │ ├── CustomPageViewSet.kt │ │ ├── DialogColorChooserExt.kt │ │ ├── utils │ │ ├── ColorExt.kt │ │ └── ViewExt.kt │ │ └── view │ │ ├── ColorCircleView.kt │ │ ├── ObservableEditText.kt │ │ ├── ObservableSeekBar.kt │ │ ├── PreviewFrameView.kt │ │ ├── SeekBarGroupLayout.kt │ │ └── WrapContentViewPager.kt │ ├── res-public │ └── values │ │ └── public.xml │ └── res │ ├── drawable-nodpi │ ├── transparent_rect.png │ └── transparentgrid.png │ ├── drawable │ ├── icon_back_black.xml │ ├── icon_back_white.xml │ ├── icon_checkmark_black.xml │ ├── icon_checkmark_white.xml │ ├── icon_custom_black.xml │ ├── icon_custom_white.xml │ └── transparent_rect_repeat.xml │ ├── layout-land │ ├── md_color_chooser_base_argb.xml │ └── md_color_chooser_base_pager.xml │ ├── layout │ ├── md_color_chooser_base_argb.xml │ ├── md_color_chooser_base_grid.xml │ ├── md_color_chooser_base_pager.xml │ ├── md_color_chooser_preview_frame.xml │ ├── md_color_grid_item.xml │ └── md_color_grid_item_go_up.xml │ ├── values-land │ ├── dimens.xml │ └── integers.xml │ ├── values-large-land │ └── integers.xml │ ├── values-large │ └── integers.xml │ └── values │ ├── dimens.xml │ ├── integers.xml │ └── styles.xml ├── core ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── afollestad │ │ └── materialdialogs │ │ ├── DialogBehavior.kt │ │ ├── LayoutMode.kt │ │ ├── MaterialDialog.kt │ │ ├── Theme.kt │ │ ├── WhichButton.kt │ │ ├── actions │ │ └── DialogActionExt.kt │ │ ├── callbacks │ │ └── DialogCallbackExt.kt │ │ ├── checkbox │ │ └── DialogCheckboxExt.kt │ │ ├── customview │ │ └── DialogCustomViewExt.kt │ │ ├── internal │ │ ├── button │ │ │ ├── DialogActionButton.kt │ │ │ └── DialogActionButtonLayout.kt │ │ ├── list │ │ │ ├── AdapterPayload.kt │ │ │ ├── DialogAdapter.kt │ │ │ ├── DialogRecyclerView.kt │ │ │ ├── MultiChoiceDialogAdapter.kt │ │ │ ├── PlainListDialogAdapter.kt │ │ │ └── SingleChoiceDialogAdapter.kt │ │ ├── main │ │ │ ├── BaseSubLayout.kt │ │ │ ├── DialogLayout.kt │ │ │ ├── DialogScrollView.kt │ │ │ └── DialogTitleLayout.kt │ │ ├── message │ │ │ ├── CustomUrlSpan.kt │ │ │ ├── DialogContentLayout.kt │ │ │ └── LinkTransformationMethod.kt │ │ └── rtl │ │ │ └── RtlTextView.kt │ │ ├── list │ │ ├── DialogListExt.kt │ │ ├── DialogMultiChoiceExt.kt │ │ ├── DialogSingleChoiceExt.kt │ │ └── ListCallbacks.kt │ │ ├── message │ │ └── DialogMessageSettings.kt │ │ └── utils │ │ ├── Arrays.kt │ │ ├── Colors.kt │ │ ├── Dialogs.kt │ │ ├── Dimens.kt │ │ ├── Fonts.kt │ │ ├── IntArrays.kt │ │ ├── MDUtil.kt │ │ └── Views.kt │ ├── res-public │ └── values │ │ └── public.xml │ └── res │ ├── anim │ ├── decelerate_cubic.xml │ ├── popup_enter.xml │ └── popup_exit.xml │ ├── color │ └── md_list_item_textcolor.xml │ ├── drawable-v21 │ ├── md_btn_selector.xml │ ├── md_btn_selector_dark.xml │ ├── md_btn_shape.xml │ ├── md_item_selector.xml │ ├── md_item_selector_dark.xml │ └── md_item_shape.xml │ ├── drawable │ ├── md_btn_selected.xml │ ├── md_btn_selected_dark.xml │ ├── md_btn_selector.xml │ ├── md_btn_selector_dark.xml │ ├── md_item_selected.xml │ ├── md_item_selected_dark.xml │ ├── md_item_selector.xml │ ├── md_item_selector_dark.xml │ ├── md_nav_back.xml │ └── md_transparent.xml │ ├── layout │ ├── md_dialog_base.xml │ ├── md_dialog_stub_buttons.xml │ ├── md_dialog_stub_message.xml │ ├── md_dialog_stub_recyclerview.xml │ ├── md_dialog_stub_scrollview.xml │ ├── md_dialog_stub_title.xml │ ├── md_listitem.xml │ ├── md_listitem_multichoice.xml │ └── md_listitem_singlechoice.xml │ ├── values-sw600dp │ └── dimens.xml │ ├── values-sw720dp-land │ └── dimens.xml │ ├── values-sw720dp │ └── dimens.xml │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ └── styles.xml ├── datetime ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── afollestad │ │ └── materialdialogs │ │ └── datetime │ │ ├── DatePickerExt.kt │ │ ├── DateTimePickerExt.kt │ │ ├── TimePickerExt.kt │ │ ├── internal │ │ ├── DateTimePickerAdapter.kt │ │ ├── TimeChangeListener.kt │ │ └── WrapContentViewPager.kt │ │ └── utils │ │ ├── DateTimeExt.kt │ │ └── ViewExt.kt │ ├── res-public │ └── values │ │ └── public.xml │ └── res │ ├── layout │ ├── md_datetime_picker_date.xml │ ├── md_datetime_picker_pager.xml │ └── md_datetime_picker_time.xml │ └── values │ └── dimens.xml ├── dependencies.gradle ├── documentation ├── BOTTOMSHEETS.md ├── COLOR.md ├── CORE.md ├── DATETIME.md ├── FILES.md ├── INPUT.md └── LIFECYCLE.md ├── files ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── afollestad │ │ └── materialdialogs │ │ └── files │ │ ├── DialogFileChooserExt.kt │ │ ├── DialogFolderChooserExt.kt │ │ ├── FileChooserAdapter.kt │ │ └── util │ │ ├── ContextExt.kt │ │ ├── FilesUtilExt.kt │ │ └── ViewExt.kt │ ├── res-public │ └── values │ │ └── public.xml │ └── res │ ├── drawable │ ├── icon_file_dark.xml │ ├── icon_file_light.xml │ ├── icon_folder_dark.xml │ ├── icon_folder_light.xml │ ├── icon_new_folder_dark.xml │ ├── icon_new_folder_light.xml │ ├── icon_return_dark.xml │ └── icon_return_light.xml │ ├── layout │ ├── md_file_chooser_base.xml │ └── md_file_chooser_item.xml │ └── values │ ├── dimens.xml │ └── strings.xml ├── gradle.properties ├── gradle ├── android_application_config.gradle ├── android_common_config.gradle ├── android_library_config.gradle ├── android_publish_mavencentral.gradle ├── spotless_plugin_config.gradle ├── versions_plugin_config.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── input ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── afollestad │ │ └── materialdialogs │ │ └── input │ │ ├── DialogInputExt.kt │ │ └── InputUtilExt.kt │ ├── res-public │ └── values │ │ └── public.xml │ └── res │ ├── layout │ └── md_dialog_stub_input.xml │ └── values │ └── dimens.xml ├── lifecycle ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── afollestad │ └── materialdialogs │ └── lifecycle │ ├── DialogLifecycleObserver.kt │ └── LifecycleExt.kt ├── sample ├── .gitignore ├── build.gradle ├── ic_web.png ├── sample.apk └── src │ ├── debug │ └── java │ │ └── com │ │ └── afollestad │ │ └── materialdialogssample │ │ └── SampleApp.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── afollestad │ │ │ └── materialdialogssample │ │ │ ├── Debouncer.kt │ │ │ ├── MainActivity.kt │ │ │ └── Utils.kt │ └── res │ │ ├── drawable │ │ └── ic_icon_android.xml │ │ ├── font │ │ ├── raleway_bold.ttf │ │ ├── raleway_medium.ttf │ │ └── raleway_semibold.ttf │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── custom_view.xml │ │ └── custom_view_webview.xml │ │ ├── menu │ │ └── main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── values-v21 │ │ └── styles_parent.xml │ │ └── values │ │ ├── arrays.xml │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ └── styles_parent.xml │ └── release │ └── java │ └── com │ └── afollestad │ └── materialdialogssample │ └── SampleApp.kt ├── settings.gradle └── spotless.license.kt /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.kt] 2 | indent_size = 2 3 | continuation_indent_size=4 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Something is crashing or not working as intended 4 | labels: bug 5 | 6 | --- 7 | 8 | *Please consider making a Pull Request if you are capable of doing so. Note that versions before 2.0.0 are no longer supported.* 9 | 10 | **Library Version:** 11 | 12 | 2.x.x 13 | 14 | **Affected Device(s):** 15 | 16 | Google Pixel 3 XL with Android 9.0 17 | 18 | **Describe the Bug:** 19 | 20 | A clear description of what is the bug is. 21 | 22 | **To Reproduce:** 23 | 1. 24 | 2. 25 | 3. 26 | 27 | **Expected Behavior:** 28 | 29 | A clear description of what you expected to happen. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | labels: improvement 5 | 6 | --- 7 | 8 | *Please consider making a Pull Request if you are capable of doing so. Note that versions before 2.0.0 are no longer supported.* 9 | 10 | **What module does this apply to?** 11 | 12 | Core? Input? Files? Color? 13 | 14 | **Description what you'd like to happen:** 15 | 16 | A clear description if the feature or behavior you'd like implemented. 17 | 18 | **Describe alternatives you've considered:** 19 | 20 | A clear description of any alternative solutions you've considered. 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Guidelines 2 | 3 | 1. You must run the `spotlessApply` task before commiting, either through Android Studio or with `./gradlew spotlessApply`. 4 | 2. A PR should be focused and contained. If you are changing multiple unrelated things, they should be in separate PRs. 5 | 3. A PR should fix a bug or solve a problem - something that only you would use is not necessarily something that should be published. 6 | 4. Give your PR a detailed title and description - look over your code one last time before actually creating the PR. Give it a self-review. 7 | 8 | **If you do not follow the guidelines, your PR will be rejected.** 9 | -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: set up JDK 1.8 13 | uses: actions/setup-java@v1 14 | with: 15 | java-version: 1.8 16 | - name: Build with Gradle 17 | run: ./gradlew build check 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io 2 | 3 | ### Android ### 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | # Proguard folder generated by Eclipse 23 | proguard/ 24 | 25 | # Log Files 26 | *.log 27 | 28 | 29 | ### Intellij ### 30 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 31 | 32 | *.iml 33 | 34 | ## Directory-based project format: 35 | .idea/ 36 | # if you remove the above rule, at least ignore the following: 37 | 38 | # User-specific stuff: 39 | # .idea/workspace.xml 40 | # .idea/tasks.xml 41 | # .idea/dictionaries 42 | 43 | # Sensitive or high-churn files: 44 | # .idea/dataSources.ids 45 | # .idea/dataSources.xml 46 | # .idea/sqlDataSources.xml 47 | # .idea/dynamic.xml 48 | # .idea/uiDesigner.xml 49 | 50 | # Gradle: 51 | # .idea/gradle.xml 52 | # .idea/libraries 53 | 54 | # Mongo Explorer plugin: 55 | # .idea/mongoSettings.xml 56 | 57 | ## File-based project format: 58 | *.ipr 59 | *.iws 60 | 61 | ## Plugin-specific files: 62 | 63 | # IntelliJ 64 | out/ 65 | 66 | # mpeltonen/sbt-idea plugin 67 | .idea_modules/ 68 | 69 | # JIRA plugin 70 | atlassian-ide-plugin.xml 71 | 72 | # Crashlytics plugin (for Android Studio and IntelliJ) 73 | com_crashlytics_export_strings.xml 74 | 75 | # Ignore Gradle GUI config 76 | gradle-app.setting 77 | 78 | # Mobile Tools for Java (J2ME) 79 | .mtj.tmp/ 80 | 81 | # Package Files # 82 | *.war 83 | *.ear 84 | 85 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 86 | hs_err_pid* 87 | 88 | *.DS_Store 89 | 90 | *.jks -------------------------------------------------------------------------------- /RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | 3.3.0 2 | 3 | * Added `md_line_spacing_body` global theme attribute, which sets a global default for message line 4 | spacing. See #1903. 5 | * Added some assertions and sanity checks to avoid choice list adapter out of bounds crashes. 6 | See #1906. 7 | * Corner radius should not apply to the bottom of bottom sheet dialogs. See #1941. 8 | * Fix dialog titles being cut off with custom fonts. See #1936. 9 | * If `noVerticalPadding` is set with `customView(...)``, padding is not applied to the bottom of 10 | the content `ScrollView` if `scrollable` is enabled. Resolves #1834. 11 | * Input dialog styling is not enforced by the dialog. The global default for `TextInputLayout` 12 | (`textInputStyle`) is used instead. See #1857. -------------------------------------------------------------------------------- /art/basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/basic.png -------------------------------------------------------------------------------- /art/basic_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/basic_list.png -------------------------------------------------------------------------------- /art/basic_with_buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/basic_with_buttons.png -------------------------------------------------------------------------------- /art/bottomsheet_customview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/bottomsheet_customview.png -------------------------------------------------------------------------------- /art/bottomsheet_peekheight.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/bottomsheet_peekheight.gif -------------------------------------------------------------------------------- /art/checkbox_prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/checkbox_prompt.png -------------------------------------------------------------------------------- /art/color_chooser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/color_chooser.png -------------------------------------------------------------------------------- /art/color_chooser_sub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/color_chooser_sub.png -------------------------------------------------------------------------------- /art/custom_argb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/custom_argb.png -------------------------------------------------------------------------------- /art/custom_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/custom_view.png -------------------------------------------------------------------------------- /art/customtheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/customtheme.png -------------------------------------------------------------------------------- /art/datepicker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/datepicker.png -------------------------------------------------------------------------------- /art/datetimepicker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/datetimepicker.png -------------------------------------------------------------------------------- /art/file_chooser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/file_chooser.png -------------------------------------------------------------------------------- /art/file_emptytext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/file_emptytext.png -------------------------------------------------------------------------------- /art/file_folder_creation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/file_folder_creation.png -------------------------------------------------------------------------------- /art/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/icon.png -------------------------------------------------------------------------------- /art/input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/input.png -------------------------------------------------------------------------------- /art/input_max_length.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/input_max_length.png -------------------------------------------------------------------------------- /art/lightanddarkthemes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/lightanddarkthemes.png -------------------------------------------------------------------------------- /art/multi_choice_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/multi_choice_list.png -------------------------------------------------------------------------------- /art/showcase4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/showcase4.png -------------------------------------------------------------------------------- /art/single_choice_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/single_choice_list.png -------------------------------------------------------------------------------- /art/stacked_buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/stacked_buttons.png -------------------------------------------------------------------------------- /art/timepicker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/art/timepicker.png -------------------------------------------------------------------------------- /bottomsheets/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /bottomsheets/build.gradle: -------------------------------------------------------------------------------- 1 | ext.module_group = "com.afollestad.material-dialogs" 2 | ext.module_name = "bottomsheets" 3 | 4 | apply from: rootProject.file("gradle/android_library_config.gradle") 5 | 6 | dependencies { 7 | api project(':core') 8 | 9 | implementation deps.kotlin.stdlib8 10 | implementation deps.google_material 11 | } 12 | -------------------------------------------------------------------------------- /bottomsheets/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bottomsheets/src/main/java/com/afollestad/materialdialogs/bottomsheets/GridItem.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.bottomsheets 17 | 18 | import android.widget.ImageView 19 | import android.widget.TextView 20 | import androidx.annotation.DrawableRes 21 | 22 | /** @author Aidan Follestad (@afollestad) */ 23 | interface GridItem { 24 | val title: String 25 | fun populateIcon(imageView: ImageView) 26 | fun configureTitle(textView: TextView) { 27 | textView.text = title 28 | } 29 | } 30 | 31 | /** @author Aidan Follestad (@afollestad) */ 32 | data class BasicGridItem( 33 | @DrawableRes val iconRes: Int, 34 | override val title: String 35 | ) : GridItem { 36 | override fun populateIcon(imageView: ImageView) { 37 | imageView.setImageResource(iconRes) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /bottomsheets/src/main/java/com/afollestad/materialdialogs/bottomsheets/HeightMatchesWidthImageView.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.bottomsheets 17 | 18 | import android.content.Context 19 | import android.util.AttributeSet 20 | import androidx.annotation.RestrictTo 21 | import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP 22 | import androidx.appcompat.widget.AppCompatImageView 23 | 24 | /** 25 | * @author Aidan Follestad (@afollestad) 26 | * @hide 27 | */ 28 | @RestrictTo(LIBRARY_GROUP) 29 | class HeightMatchesWidthImageView( 30 | context: Context, 31 | attrs: AttributeSet? 32 | ) : AppCompatImageView(context, attrs) { 33 | 34 | override fun onMeasure( 35 | widthMeasureSpec: Int, 36 | heightMeasureSpec: Int 37 | ) = super.onMeasure(widthMeasureSpec, widthMeasureSpec) 38 | } 39 | -------------------------------------------------------------------------------- /bottomsheets/src/main/res-public/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /bottomsheets/src/main/res/layout/md_dialog_base_bottomsheet.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 23 | 24 | 25 | 26 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /bottomsheets/src/main/res/layout/md_dialog_base_no_buttons.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /bottomsheets/src/main/res/layout/md_griditem.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 19 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /bottomsheets/src/main/res/values-land/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 4 | 5 | -------------------------------------------------------------------------------- /bottomsheets/src/main/res/values-large-land/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 4 | 5 | -------------------------------------------------------------------------------- /bottomsheets/src/main/res/values-large/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 4 | 5 | -------------------------------------------------------------------------------- /bottomsheets/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /bottomsheets/src/main/res/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 4 | 5 | -------------------------------------------------------------------------------- /bottomsheets/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 13 | 14 | 21 | 22 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply from: rootProject.file("gradle/versions_plugin_config.gradle") 2 | 3 | buildscript { 4 | apply from: rootProject.file("dependencies.gradle") 5 | 6 | repositories { 7 | google() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath deps.gradle_plugins.android 13 | classpath deps.gradle_plugins.kotlin 14 | classpath deps.gradle_plugins.spotless 15 | classpath deps.gradle_plugins.versions 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | google() 22 | jcenter() 23 | } 24 | } 25 | 26 | subprojects { 27 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { 28 | kotlinOptions { 29 | freeCompilerArgs += ['-module-name', project.path.replace(':', '')] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /color/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /color/build.gradle: -------------------------------------------------------------------------------- 1 | ext.module_group = "com.afollestad.material-dialogs" 2 | ext.module_name = "color" 3 | 4 | apply from: rootProject.file("gradle/android_library_config.gradle") 5 | 6 | dependencies { 7 | api project(':core') 8 | 9 | implementation deps.kotlin.stdlib8 10 | implementation deps.afollestad.dots_indicator 11 | } 12 | -------------------------------------------------------------------------------- /color/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /color/src/main/java/com/afollestad/materialdialogs/color/ColorPagerAdapter.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.color 17 | 18 | import android.view.View 19 | import android.view.ViewGroup 20 | import androidx.viewpager.widget.PagerAdapter 21 | 22 | internal class ColorPagerAdapter : PagerAdapter() { 23 | 24 | override fun instantiateItem( 25 | collection: ViewGroup, 26 | position: Int 27 | ): Any { 28 | var resId = 0 29 | when (position) { 30 | 0 -> resId = R.id.colorPresetGrid 31 | 1 -> resId = R.id.colorArgbPage 32 | } 33 | return collection.findViewById(resId) 34 | } 35 | 36 | override fun getCount() = 2 37 | 38 | override fun isViewFromObject( 39 | arg0: View, 40 | arg1: Any 41 | ) = arg0 === arg1 as View 42 | 43 | override fun destroyItem( 44 | container: ViewGroup, 45 | position: Int, 46 | arg1: Any 47 | ) = Unit 48 | } 49 | -------------------------------------------------------------------------------- /color/src/main/java/com/afollestad/materialdialogs/color/utils/ColorExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.color.utils 17 | 18 | import android.graphics.Color 19 | 20 | internal fun Int.hexValue(includeAlpha: Boolean) = if (this == 0) { 21 | if (includeAlpha) "00000000" else "000000" 22 | } else { 23 | if (includeAlpha) { 24 | val result = Integer.toHexString(this) 25 | if (result.length == 6) { 26 | "00$result" 27 | } else { 28 | result 29 | } 30 | } else { 31 | String.format("%06X", 0xFFFFFF and this) 32 | } 33 | } 34 | 35 | internal fun String.toColor(): Int? { 36 | return try { 37 | Color.parseColor("#$this") 38 | } catch (_: Exception) { 39 | null 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /color/src/main/java/com/afollestad/materialdialogs/color/utils/ViewExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.color.utils 17 | 18 | import android.view.View 19 | import android.view.View.GONE 20 | import android.view.View.INVISIBLE 21 | import android.view.View.VISIBLE 22 | import android.view.ViewGroup.MarginLayoutParams 23 | import android.widget.RelativeLayout 24 | import androidx.annotation.IdRes 25 | import androidx.viewpager.widget.ViewPager 26 | 27 | internal fun T.setVisibleOrGone(visible: Boolean) { 28 | visibility = if (visible) VISIBLE else GONE 29 | } 30 | 31 | internal fun ViewPager.onPageSelected(selection: (Int) -> Unit) { 32 | addOnPageChangeListener(object : ViewPager.OnPageChangeListener { 33 | override fun onPageSelected(position: Int) = selection(position) 34 | 35 | override fun onPageScrollStateChanged(state: Int) = Unit 36 | 37 | override fun onPageScrolled( 38 | position: Int, 39 | positionOffset: Float, 40 | positionOffsetPixels: Int 41 | ) = Unit 42 | }) 43 | } 44 | 45 | internal fun View.changeHeight(height: Int) { 46 | if (height == 0) { 47 | visibility = INVISIBLE 48 | } 49 | val lp = layoutParams as MarginLayoutParams 50 | lp.height = height 51 | layoutParams = lp 52 | } 53 | 54 | internal fun View.below(@IdRes id: Int) { 55 | val lp = layoutParams as RelativeLayout.LayoutParams 56 | lp.addRule(RelativeLayout.BELOW, id) 57 | layoutParams = lp 58 | } 59 | 60 | internal fun View.clearTopMargin() { 61 | val lp = this.layoutParams as MarginLayoutParams 62 | lp.topMargin = 0 63 | layoutParams = lp 64 | parent.requestLayout() 65 | } 66 | -------------------------------------------------------------------------------- /color/src/main/java/com/afollestad/materialdialogs/color/view/ColorCircleView.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.color.view 17 | 18 | import android.content.Context 19 | import android.graphics.Canvas 20 | import android.graphics.Color 21 | import android.graphics.Color.TRANSPARENT 22 | import android.graphics.Paint 23 | import android.graphics.Paint.Style.FILL 24 | import android.graphics.Paint.Style.STROKE 25 | import android.graphics.drawable.Drawable 26 | import android.util.AttributeSet 27 | import android.view.View 28 | import androidx.annotation.ColorInt 29 | import androidx.core.content.ContextCompat.getDrawable 30 | import com.afollestad.materialdialogs.color.R.dimen 31 | import com.afollestad.materialdialogs.color.R.drawable 32 | import com.afollestad.materialdialogs.utils.MDUtil.dimenPx 33 | 34 | /** @author Aidan Follestad (afollestad) */ 35 | internal class ColorCircleView( 36 | context: Context, 37 | attrs: AttributeSet? = null 38 | ) : View(context, attrs) { 39 | 40 | private val strokePaint = Paint() 41 | private val fillPaint = Paint() 42 | 43 | private val borderWidth = dimenPx( 44 | dimen.color_circle_view_border 45 | ) 46 | 47 | private var transparentGrid: Drawable? = null 48 | 49 | init { 50 | setWillNotDraw(false) 51 | strokePaint.style = STROKE 52 | strokePaint.isAntiAlias = true 53 | strokePaint.color = Color.BLACK 54 | strokePaint.strokeWidth = borderWidth.toFloat() 55 | fillPaint.style = FILL 56 | fillPaint.isAntiAlias = true 57 | fillPaint.color = Color.DKGRAY 58 | } 59 | 60 | @ColorInt var color: Int = Color.BLACK 61 | set(value) { 62 | field = value 63 | fillPaint.color = value 64 | invalidate() 65 | } 66 | @ColorInt var border: Int = Color.DKGRAY 67 | set(value) { 68 | field = value 69 | strokePaint.color = value 70 | invalidate() 71 | } 72 | 73 | override fun onMeasure( 74 | widthMeasureSpec: Int, 75 | heightMeasureSpec: Int 76 | ) = super.onMeasure(widthMeasureSpec, widthMeasureSpec) 77 | 78 | override fun onDraw(canvas: Canvas) { 79 | super.onDraw(canvas) 80 | if (color == TRANSPARENT) { 81 | if (transparentGrid == null) { 82 | transparentGrid = getDrawable(context, 83 | drawable.transparentgrid 84 | ) 85 | } 86 | transparentGrid?.setBounds(0, 0, measuredWidth, measuredHeight) 87 | transparentGrid?.draw(canvas) 88 | } else { 89 | canvas.drawCircle( 90 | measuredWidth / 2f, 91 | measuredHeight / 2f, 92 | (measuredWidth / 2f) - borderWidth, 93 | fillPaint 94 | ) 95 | } 96 | canvas.drawCircle( 97 | measuredWidth / 2f, 98 | measuredHeight / 2f, 99 | (measuredWidth / 2f) - borderWidth, 100 | strokePaint 101 | ) 102 | } 103 | 104 | override fun onDetachedFromWindow() { 105 | super.onDetachedFromWindow() 106 | transparentGrid = null 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /color/src/main/java/com/afollestad/materialdialogs/color/view/ObservableEditText.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | @file:Suppress("MemberVisibilityCanBePrivate", "unused") 17 | 18 | package com.afollestad.materialdialogs.color.view 19 | 20 | import android.content.Context 21 | import android.text.Editable 22 | import android.text.TextWatcher 23 | import android.util.AttributeSet 24 | import androidx.annotation.StringRes 25 | import androidx.appcompat.widget.AppCompatEditText 26 | 27 | typealias TextListener = ((String) -> Unit)? 28 | 29 | /** @author Aidan Follestad (@afollestad) */ 30 | class ObservableEditText( 31 | context: Context, 32 | attrs: AttributeSet? = null 33 | ) : AppCompatEditText(context, attrs) { 34 | 35 | private var listener: TextListener = null 36 | private var paused: Boolean = false 37 | 38 | val textOrEmpty: String 39 | get() = text?.toString()?.trim() ?: "" 40 | val textLength: Int get() = textOrEmpty.length 41 | 42 | override fun onAttachedToWindow() { 43 | super.onAttachedToWindow() 44 | addTextChangedListener(watcher) 45 | } 46 | 47 | override fun onDetachedFromWindow() { 48 | super.onDetachedFromWindow() 49 | removeTextChangedListener(watcher) 50 | } 51 | 52 | fun observe(listener: TextListener) { 53 | this.listener = listener 54 | } 55 | 56 | fun updateText(text: CharSequence) { 57 | paused = true 58 | setText(text) 59 | } 60 | 61 | fun updateText(@StringRes res: Int) { 62 | paused = true 63 | setText(res) 64 | } 65 | 66 | private val watcher = object : TextWatcher { 67 | override fun beforeTextChanged( 68 | s: CharSequence?, 69 | start: Int, 70 | count: Int, 71 | after: Int 72 | ) = Unit 73 | 74 | override fun onTextChanged( 75 | s: CharSequence, 76 | start: Int, 77 | before: Int, 78 | count: Int 79 | ) { 80 | if (!paused) { 81 | listener?.invoke(s.toString()) 82 | } 83 | } 84 | 85 | override fun afterTextChanged(s: Editable?) { 86 | paused = false 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /color/src/main/java/com/afollestad/materialdialogs/color/view/ObservableSeekBar.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.color.view 17 | 18 | import android.content.Context 19 | import android.os.Build 20 | import android.util.AttributeSet 21 | import android.widget.SeekBar 22 | import androidx.appcompat.widget.AppCompatSeekBar 23 | 24 | typealias ProgressListener = ((Int) -> Unit)? 25 | 26 | /** @author Aidan Follestad (@afollestad) */ 27 | class ObservableSeekBar( 28 | context: Context, 29 | attrs: AttributeSet? = null 30 | ) : AppCompatSeekBar(context, attrs) { 31 | 32 | private var listener: ProgressListener = null 33 | private var paused: Boolean = false 34 | private var onlyFromUser: Boolean = false 35 | 36 | override fun onAttachedToWindow() { 37 | super.onAttachedToWindow() 38 | setOnSeekBarChangeListener(watcher) 39 | } 40 | 41 | override fun onDetachedFromWindow() { 42 | setOnSeekBarChangeListener(null) 43 | super.onDetachedFromWindow() 44 | } 45 | 46 | fun observe( 47 | onlyFromUser: Boolean = true, 48 | listener: ProgressListener 49 | ) { 50 | this.onlyFromUser = onlyFromUser 51 | this.listener = listener 52 | } 53 | 54 | fun updateProgress( 55 | progress: Int, 56 | animate: Boolean = false 57 | ) { 58 | paused = true 59 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 60 | setProgress(progress, animate) 61 | } else { 62 | setProgress(progress) 63 | } 64 | } 65 | 66 | private val watcher = object : OnSeekBarChangeListener { 67 | override fun onProgressChanged( 68 | seekBar: SeekBar, 69 | progress: Int, 70 | fromUser: Boolean 71 | ) { 72 | if (!onlyFromUser || fromUser) { 73 | listener?.invoke(progress) 74 | } 75 | paused = false 76 | } 77 | 78 | override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit 79 | 80 | override fun onStopTrackingTouch(seekBar: SeekBar?) = Unit 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /color/src/main/java/com/afollestad/materialdialogs/color/view/WrapContentViewPager.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.color.view 17 | 18 | import android.content.Context 19 | import android.util.AttributeSet 20 | import android.view.View 21 | import android.view.View.MeasureSpec.EXACTLY 22 | import android.view.View.MeasureSpec.UNSPECIFIED 23 | import android.view.View.MeasureSpec.makeMeasureSpec 24 | import androidx.viewpager.widget.ViewPager 25 | import com.afollestad.materialdialogs.utils.MDUtil.ifNotZero 26 | 27 | internal class WrapContentViewPager( 28 | context: Context, 29 | attrs: AttributeSet? = null 30 | ) : ViewPager(context, attrs) { 31 | 32 | override fun onMeasure( 33 | widthMeasureSpec: Int, 34 | heightMeasureSpec: Int 35 | ) { 36 | var newHeightSpec = heightMeasureSpec 37 | 38 | var maxChildHeight = 0 39 | forEachChild { child -> 40 | child.measure( 41 | widthMeasureSpec, 42 | makeMeasureSpec(0, UNSPECIFIED) 43 | ) 44 | 45 | val h = child.measuredHeight 46 | if (h > maxChildHeight) { 47 | maxChildHeight = h 48 | } 49 | } 50 | 51 | val maxAllowedHeightFromParent = MeasureSpec.getSize(heightMeasureSpec) 52 | if (maxChildHeight > maxAllowedHeightFromParent) { 53 | maxChildHeight = maxAllowedHeightFromParent 54 | } 55 | maxChildHeight.ifNotZero { 56 | newHeightSpec = makeMeasureSpec(it, EXACTLY) 57 | } 58 | 59 | super.onMeasure(widthMeasureSpec, newHeightSpec) 60 | } 61 | 62 | private fun forEachChild(each: (View) -> Unit) { 63 | for (i in 0 until childCount) { 64 | val child = getChildAt(i) 65 | each(child) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /color/src/main/res-public/values/public.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /color/src/main/res/drawable-nodpi/transparent_rect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/color/src/main/res/drawable-nodpi/transparent_rect.png -------------------------------------------------------------------------------- /color/src/main/res/drawable-nodpi/transparentgrid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/color/src/main/res/drawable-nodpi/transparentgrid.png -------------------------------------------------------------------------------- /color/src/main/res/drawable/icon_back_black.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /color/src/main/res/drawable/icon_back_white.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /color/src/main/res/drawable/icon_checkmark_black.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /color/src/main/res/drawable/icon_checkmark_white.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /color/src/main/res/drawable/icon_custom_black.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /color/src/main/res/drawable/icon_custom_white.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /color/src/main/res/drawable/transparent_rect_repeat.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /color/src/main/res/layout-land/md_color_chooser_base_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /color/src/main/res/layout/md_color_chooser_base_grid.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | -------------------------------------------------------------------------------- /color/src/main/res/layout/md_color_chooser_base_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /color/src/main/res/layout/md_color_chooser_preview_frame.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 17 | 18 | 25 | 26 | 33 | 34 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /color/src/main/res/layout/md_color_grid_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /color/src/main/res/layout/md_color_grid_item_go_up.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /color/src/main/res/values-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4dp 5 | 12dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /color/src/main/res/values-land/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 4 | 5 | -------------------------------------------------------------------------------- /color/src/main/res/values-large-land/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 4 | 5 | -------------------------------------------------------------------------------- /color/src/main/res/values-large/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 4 | 5 | -------------------------------------------------------------------------------- /color/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1dp 4 | 5 | 8dp 6 | 16dp 7 | 12dp 8 | 9 | 24dp 10 | 8dp 11 | 12 | 72dp 13 | 120dp 14 | 8dp 15 | 8dp 16 | 17 | 18sp 18 | 20dp 19 | 8dp 20 | 21 | 36dp 22 | 23 | 24 | -------------------------------------------------------------------------------- /color/src/main/res/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 4 | 5 | -------------------------------------------------------------------------------- /color/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 15 | 16 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /core/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /core/build.gradle: -------------------------------------------------------------------------------- 1 | ext.module_group = "com.afollestad.material-dialogs" 2 | ext.module_name = "core" 3 | 4 | apply from: rootProject.file("gradle/android_library_config.gradle") 5 | 6 | dependencies { 7 | api deps.androidx.core 8 | api deps.androidx.recycler_view 9 | compileOnly deps.androidx.annotations 10 | 11 | implementation deps.kotlin.stdlib8 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/LayoutMode.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs 17 | 18 | /** @author Aidan Follestad (afollestad) */ 19 | enum class LayoutMode { 20 | /** The layout height fills in the screen. */ 21 | MATCH_PARENT, 22 | /** 23 | * The layout height wraps its children, maxing out at the screen height in which case the 24 | * children should be inside of a ScrollView. 25 | */ 26 | WRAP_CONTENT 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/Theme.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs 17 | 18 | import android.R.attr 19 | import android.content.Context 20 | import androidx.annotation.CheckResult 21 | import androidx.annotation.StyleRes 22 | import com.afollestad.materialdialogs.utils.MDUtil.isColorDark 23 | import com.afollestad.materialdialogs.utils.MDUtil.resolveColor 24 | 25 | @StyleRes @CheckResult 26 | internal fun inferTheme( 27 | context: Context, 28 | dialogBehavior: DialogBehavior 29 | ): Int { 30 | val isThemeDark = !inferThemeIsLight(context) 31 | return dialogBehavior.getThemeRes(isThemeDark) 32 | } 33 | 34 | @CheckResult internal fun inferThemeIsLight(context: Context): Boolean { 35 | return resolveColor(context = context, attr = attr.textColorPrimary).isColorDark() 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/WhichButton.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs 17 | 18 | import com.afollestad.materialdialogs.internal.button.DialogActionButtonLayout.Companion.INDEX_NEGATIVE 19 | import com.afollestad.materialdialogs.internal.button.DialogActionButtonLayout.Companion.INDEX_NEUTRAL 20 | import com.afollestad.materialdialogs.internal.button.DialogActionButtonLayout.Companion.INDEX_POSITIVE 21 | 22 | enum class WhichButton(val index: Int) { 23 | POSITIVE(INDEX_POSITIVE), 24 | NEGATIVE(INDEX_NEGATIVE), 25 | NEUTRAL(INDEX_NEUTRAL); 26 | 27 | companion object { 28 | fun fromIndex(index: Int) = when (index) { 29 | INDEX_POSITIVE -> POSITIVE 30 | INDEX_NEGATIVE -> NEGATIVE 31 | INDEX_NEUTRAL -> NEUTRAL 32 | else -> throw IndexOutOfBoundsException("$index is not an action button index.") 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/actions/DialogActionExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.actions 17 | 18 | import com.afollestad.materialdialogs.MaterialDialog 19 | import com.afollestad.materialdialogs.WhichButton 20 | import com.afollestad.materialdialogs.internal.button.DialogActionButton 21 | import com.afollestad.materialdialogs.utils.isVisible 22 | 23 | /** Returns true if the dialog has visible action buttons. */ 24 | fun MaterialDialog.hasActionButtons(): Boolean { 25 | return view.buttonsLayout?.visibleButtons?.isNotEmpty() ?: false 26 | } 27 | 28 | /** Returns true if the given button is visible in the dialog. */ 29 | fun MaterialDialog.hasActionButton(which: WhichButton) = getActionButton(which).isVisible() 30 | 31 | /** Returns the underlying view for an action button in the dialog. */ 32 | fun MaterialDialog.getActionButton(which: WhichButton): DialogActionButton { 33 | return view.buttonsLayout?.actionButtons?.get(which.index) ?: throw IllegalStateException( 34 | "The dialog does not have an attached buttons layout." 35 | ) 36 | } 37 | 38 | /** Enables or disables an action button. */ 39 | fun MaterialDialog.setActionButtonEnabled( 40 | which: WhichButton, 41 | enabled: Boolean 42 | ) { 43 | getActionButton(which).isEnabled = enabled 44 | } 45 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/callbacks/DialogCallbackExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.callbacks 17 | 18 | import com.afollestad.materialdialogs.DialogCallback 19 | import com.afollestad.materialdialogs.MaterialDialog 20 | 21 | /** 22 | * Adds a listener that's invoked right before the dialog is [MaterialDialog.show]'n. If this is called 23 | * multiple times, it appends additional callbacks, rather than overwriting. 24 | */ 25 | fun MaterialDialog.onPreShow(callback: DialogCallback): MaterialDialog { 26 | this.preShowListeners.add(callback) 27 | return this 28 | } 29 | 30 | /** 31 | * Adds a listener that's invoked when the dialog is [MaterialDialog.show]'n. If this is called 32 | * multiple times, it appends additional callbacks, rather than overwriting. 33 | * 34 | * If the dialog is already showing, the callback be will be invoked immediately. 35 | */ 36 | fun MaterialDialog.onShow(callback: DialogCallback): MaterialDialog { 37 | this.showListeners.add(callback) 38 | if (this.isShowing) { 39 | // Already showing, invoke now 40 | this.showListeners.invokeAll(this) 41 | } 42 | setOnShowListener { this.showListeners.invokeAll(this) } 43 | return this 44 | } 45 | 46 | /** 47 | * Adds a listener that's invoked when the dialog is [MaterialDialog.dismiss]'d. If this is called 48 | * multiple times, it appends additional callbacks, rather than overwriting. 49 | */ 50 | fun MaterialDialog.onDismiss(callback: DialogCallback): MaterialDialog { 51 | this.dismissListeners.add(callback) 52 | setOnDismissListener { dismissListeners.invokeAll(this) } 53 | return this 54 | } 55 | 56 | /** 57 | * Adds a listener that's invoked when the dialog is [MaterialDialog.cancel]'d. If this is called 58 | * multiple times, it appends additional callbacks, rather than overwriting. 59 | */ 60 | fun MaterialDialog.onCancel(callback: DialogCallback): MaterialDialog { 61 | this.cancelListeners.add(callback) 62 | setOnCancelListener { cancelListeners.invokeAll(this) } 63 | return this 64 | } 65 | 66 | internal fun MutableList.invokeAll(dialog: MaterialDialog) { 67 | for (callback in this) { 68 | callback.invoke(dialog) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/checkbox/DialogCheckboxExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | @file:Suppress("unused") 17 | 18 | package com.afollestad.materialdialogs.checkbox 19 | 20 | import android.view.View 21 | import android.widget.CheckBox 22 | import androidx.annotation.CheckResult 23 | import androidx.annotation.StringRes 24 | import androidx.core.widget.CompoundButtonCompat 25 | import com.afollestad.materialdialogs.MaterialDialog 26 | import com.afollestad.materialdialogs.R 27 | import com.afollestad.materialdialogs.utils.MDUtil.assertOneSet 28 | import com.afollestad.materialdialogs.utils.MDUtil.createColorSelector 29 | import com.afollestad.materialdialogs.utils.MDUtil.maybeSetTextColor 30 | import com.afollestad.materialdialogs.utils.MDUtil.resolveString 31 | import com.afollestad.materialdialogs.utils.resolveColors 32 | 33 | typealias BooleanCallback = ((Boolean) -> Unit)? 34 | 35 | @CheckResult fun MaterialDialog.getCheckBoxPrompt(): CheckBox { 36 | return view.buttonsLayout?.checkBoxPrompt ?: throw IllegalStateException( 37 | "The dialog does not have an attached buttons layout." 38 | ) 39 | } 40 | 41 | @CheckResult fun MaterialDialog.isCheckPromptChecked() = getCheckBoxPrompt().isChecked 42 | 43 | /** 44 | * @param res The string resource to display for the checkbox label. 45 | * @param text The literal string to display for the checkbox label. 46 | * @param isCheckedDefault Whether or not the checkbox is initially checked. 47 | * @param onToggle A listener invoked when the checkbox is checked or unchecked. 48 | */ 49 | fun MaterialDialog.checkBoxPrompt( 50 | @StringRes res: Int = 0, 51 | text: String? = null, 52 | isCheckedDefault: Boolean = false, 53 | onToggle: BooleanCallback 54 | ): MaterialDialog { 55 | assertOneSet("checkBoxPrompt", text, res) 56 | view.buttonsLayout?.checkBoxPrompt?.run { 57 | this.visibility = View.VISIBLE 58 | this.text = text ?: resolveString(this@checkBoxPrompt, res) 59 | this.isChecked = isCheckedDefault 60 | this.setOnCheckedChangeListener { _, checked -> 61 | onToggle?.invoke(checked) 62 | } 63 | maybeSetTextColor(windowContext, R.attr.md_color_content) 64 | bodyFont?.let(this::setTypeface) 65 | 66 | val widgetAttrs = intArrayOf(R.attr.md_color_widget, R.attr.md_color_widget_unchecked) 67 | resolveColors(attrs = widgetAttrs).let { 68 | CompoundButtonCompat.setButtonTintList( 69 | this, 70 | createColorSelector(windowContext, checked = it[0], unchecked = it[1]) 71 | ) 72 | } 73 | } 74 | return this 75 | } 76 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/customview/DialogCustomViewExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.customview 17 | 18 | import android.view.View 19 | import androidx.annotation.CheckResult 20 | import androidx.annotation.LayoutRes 21 | import com.afollestad.materialdialogs.MaterialDialog 22 | import com.afollestad.materialdialogs.utils.MDUtil.assertOneSet 23 | import com.afollestad.materialdialogs.utils.MDUtil.waitForWidth 24 | 25 | internal const val CUSTOM_VIEW_NO_VERTICAL_PADDING = "md.custom_view_no_vertical_padding" 26 | 27 | /** 28 | * Gets the custom view for the dialog, set by [customView]. 29 | * 30 | * @throws IllegalStateException if there is no custom view set. 31 | */ 32 | @CheckResult fun MaterialDialog.getCustomView(): View { 33 | return this.view.contentLayout.customView 34 | ?: error("You have not setup this dialog as a customView dialog.") 35 | } 36 | 37 | /** 38 | * Sets a custom view to display in the dialog, below the title and above the action buttons 39 | * (and checkbox prompt). 40 | * 41 | * @param viewRes The layout resource to inflate as the custom view. 42 | * @param view The view to insert as the custom view. 43 | * @param scrollable Whether or not the custom view is automatically wrapped in a ScrollView. 44 | * @param noVerticalPadding When set to true, vertical padding is not added around your content. 45 | * @param horizontalPadding When true, 24dp horizontal padding is applied to your custom view. 46 | * @param dialogWrapContent When true, the dialog will wrap the content width. 47 | */ 48 | fun MaterialDialog.customView( 49 | @LayoutRes viewRes: Int? = null, 50 | view: View? = null, 51 | scrollable: Boolean = false, 52 | noVerticalPadding: Boolean = false, 53 | horizontalPadding: Boolean = false, 54 | dialogWrapContent: Boolean = false 55 | ): MaterialDialog { 56 | assertOneSet("customView", view, viewRes) 57 | config[CUSTOM_VIEW_NO_VERTICAL_PADDING] = noVerticalPadding 58 | 59 | if (dialogWrapContent) { 60 | // Postpone window measurement so custom view measures itself naturally. 61 | maxWidth(literal = 0) 62 | } 63 | 64 | this.view.contentLayout 65 | .addCustomView( 66 | res = viewRes, 67 | view = view, 68 | scrollable = scrollable, 69 | horizontalPadding = horizontalPadding, 70 | noVerticalPadding = noVerticalPadding 71 | ) 72 | .also { 73 | if (dialogWrapContent) { 74 | it.waitForWidth { 75 | maxWidth(literal = measuredWidth) 76 | } 77 | } 78 | } 79 | 80 | return this 81 | } 82 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/internal/list/AdapterPayload.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.internal.list 17 | 18 | /** 19 | * Used by the single and multi-choice list adapters to selectively bind list items. This 20 | * payload indicates that the notified list item should check its toggleable view. 21 | */ 22 | internal object CheckPayload 23 | 24 | /** 25 | * Used by the single and multi-choice list adapters to selectively bind list items. This 26 | * payload indicates that the notified list item should uncheck its toggleable view. 27 | */ 28 | internal object UncheckPayload 29 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/internal/list/DialogAdapter.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.internal.list 17 | 18 | interface DialogAdapter { 19 | fun replaceItems( 20 | items: List, 21 | listener: SL? = null 22 | ) 23 | 24 | fun disableItems(indices: IntArray) 25 | 26 | fun checkItems(indices: IntArray) 27 | 28 | fun uncheckItems(indices: IntArray) 29 | 30 | fun toggleItems(indices: IntArray) 31 | 32 | fun checkAllItems() 33 | 34 | fun uncheckAllItems() 35 | 36 | fun toggleAllChecked() 37 | 38 | fun isItemChecked(index: Int): Boolean 39 | 40 | fun getItemCount(): Int 41 | 42 | fun positiveButtonClicked() 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/internal/main/BaseSubLayout.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.internal.main 17 | 18 | import android.content.Context 19 | import android.graphics.Paint 20 | import android.graphics.Paint.Style.STROKE 21 | import android.util.AttributeSet 22 | import android.view.ViewGroup 23 | import androidx.annotation.RestrictTo 24 | import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP 25 | import com.afollestad.materialdialogs.MaterialDialog 26 | import com.afollestad.materialdialogs.R 27 | import com.afollestad.materialdialogs.R.attr 28 | import com.afollestad.materialdialogs.utils.MDUtil.dimenPx 29 | import com.afollestad.materialdialogs.utils.MDUtil.resolveColor 30 | 31 | @RestrictTo(LIBRARY_GROUP) 32 | abstract class BaseSubLayout internal constructor( 33 | context: Context, 34 | attrs: AttributeSet? = null 35 | ) : ViewGroup(context, attrs) { 36 | 37 | private val dividerPaint = Paint() 38 | protected val dividerHeight = dimenPx(R.dimen.md_divider_height) 39 | lateinit var dialog: MaterialDialog 40 | 41 | var drawDivider: Boolean = false 42 | set(value) { 43 | field = value 44 | invalidate() 45 | } 46 | 47 | init { 48 | @Suppress("LeakingThis") 49 | setWillNotDraw(false) 50 | dividerPaint.style = STROKE 51 | dividerPaint.strokeWidth = context.resources.getDimension(R.dimen.md_divider_height) 52 | dividerPaint.isAntiAlias = true 53 | } 54 | 55 | protected fun dividerPaint(): Paint { 56 | dividerPaint.color = getDividerColor() 57 | return dividerPaint 58 | } 59 | 60 | private fun getDividerColor(): Int { 61 | return resolveColor(dialog.context, attr = attr.md_divider_color) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/internal/main/DialogScrollView.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.internal.main 17 | 18 | import android.content.Context 19 | import android.util.AttributeSet 20 | import android.widget.ScrollView 21 | import androidx.annotation.RestrictTo 22 | import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP 23 | import com.afollestad.materialdialogs.utils.MDUtil.waitForWidth 24 | 25 | /** 26 | * A [ScrollView] which reports whether or not it's scrollable based on whether the content 27 | * is shorter than the ScrollView itself. Also reports back to an [DialogLayout] to invalidate 28 | * dividers. 29 | * 30 | * @author Aidan Follestad (afollestad) 31 | */ 32 | @RestrictTo(LIBRARY_GROUP) 33 | class DialogScrollView( 34 | context: Context?, 35 | attrs: AttributeSet? = null 36 | ) : ScrollView(context, attrs) { 37 | 38 | var rootView: DialogLayout? = null 39 | 40 | private val isScrollable: Boolean 41 | get() = getChildAt(0).measuredHeight > height 42 | 43 | override fun onAttachedToWindow() { 44 | super.onAttachedToWindow() 45 | waitForWidth { 46 | invalidateDividers() 47 | invalidateOverScroll() 48 | } 49 | } 50 | 51 | override fun onScrollChanged( 52 | left: Int, 53 | top: Int, 54 | oldl: Int, 55 | oldt: Int 56 | ) { 57 | super.onScrollChanged(left, top, oldl, oldt) 58 | invalidateDividers() 59 | } 60 | 61 | fun invalidateDividers() { 62 | if (childCount == 0 || measuredHeight == 0 || !isScrollable) { 63 | rootView?.invalidateDividers(showTop = false, showBottom = false) 64 | return 65 | } 66 | val view = getChildAt(childCount - 1) 67 | val diff = view.bottom - (measuredHeight + scrollY) 68 | rootView?.invalidateDividers( 69 | scrollY > 0, 70 | diff > 0 71 | ) 72 | } 73 | 74 | private fun invalidateOverScroll() { 75 | overScrollMode = if (childCount == 0 || measuredHeight == 0 || !isScrollable) { 76 | OVER_SCROLL_NEVER 77 | } else { 78 | OVER_SCROLL_IF_CONTENT_SCROLLS 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/internal/message/CustomUrlSpan.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | @file:Suppress("unused") 17 | 18 | package com.afollestad.materialdialogs.internal.message 19 | 20 | import android.text.style.URLSpan 21 | import android.view.View 22 | 23 | /** @author Aidan Follestad (@afollestad) */ 24 | class CustomUrlSpan( 25 | url: String, 26 | private val onLinkClick: (String) -> Unit 27 | ) : URLSpan(url) { 28 | override fun onClick(widget: View) = onLinkClick(url) 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/internal/message/LinkTransformationMethod.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.internal.message 17 | 18 | import android.graphics.Rect 19 | import android.text.Spannable 20 | import android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE 21 | import android.text.method.TransformationMethod 22 | import android.text.style.URLSpan 23 | import android.view.View 24 | import android.widget.TextView 25 | 26 | /** https://medium.com/@nullthemall/make-textview-open-links-in-customtabs-12fdcf4bb684 */ 27 | internal class LinkTransformationMethod( 28 | private val onLinkClick: (link: String) -> Unit 29 | ) : TransformationMethod { 30 | override fun getTransformation( 31 | source: CharSequence, 32 | view: View 33 | ): CharSequence { 34 | if (view !is TextView) { 35 | return source 36 | } else if (view.text == null || view.text !is Spannable) { 37 | return source 38 | } 39 | val text = view.text as Spannable 40 | val spans = text.getSpans(0, view.length(), URLSpan::class.java) 41 | for (span in spans) { 42 | val start = text.getSpanStart(span) 43 | val end = text.getSpanEnd(span) 44 | val url = span.url 45 | 46 | text.removeSpan(span) 47 | text.setSpan(CustomUrlSpan(url, onLinkClick), start, end, SPAN_EXCLUSIVE_EXCLUSIVE) 48 | } 49 | return text 50 | } 51 | 52 | override fun onFocusChanged( 53 | view: View, 54 | sourceText: CharSequence, 55 | focused: Boolean, 56 | direction: Int, 57 | previouslyFocusedRect: Rect 58 | ) = Unit 59 | } 60 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/internal/rtl/RtlTextView.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.internal.rtl 17 | 18 | import android.content.Context 19 | import android.util.AttributeSet 20 | import androidx.appcompat.widget.AppCompatTextView 21 | import com.afollestad.materialdialogs.utils.setGravityStartCompat 22 | 23 | /** 24 | * With our custom layout-ing, using START/END gravity doesn't work so we manually 25 | * set text alignment for RTL/LTR. 26 | * 27 | * @author Aidan Follestad (afollestad) 28 | */ 29 | class RtlTextView( 30 | context: Context, 31 | attrs: AttributeSet? 32 | ) : AppCompatTextView(context, attrs) { 33 | init { 34 | setGravityStartCompat() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/list/ListCallbacks.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.list 17 | 18 | import com.afollestad.materialdialogs.MaterialDialog 19 | 20 | typealias ItemListener = 21 | ((dialog: MaterialDialog, index: Int, text: CharSequence) -> Unit)? 22 | 23 | typealias SingleChoiceListener = 24 | ((dialog: MaterialDialog, index: Int, text: CharSequence) -> Unit)? 25 | 26 | typealias MultiChoiceListener = 27 | ((dialog: MaterialDialog, indices: IntArray, items: List) -> Unit)? 28 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/message/DialogMessageSettings.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.message 17 | 18 | import android.text.Html 19 | import android.text.method.LinkMovementMethod 20 | import android.widget.TextView 21 | import androidx.annotation.StringRes 22 | import com.afollestad.materialdialogs.MaterialDialog 23 | import com.afollestad.materialdialogs.R 24 | import com.afollestad.materialdialogs.internal.message.LinkTransformationMethod 25 | import com.afollestad.materialdialogs.utils.MDUtil.resolveFloat 26 | import com.afollestad.materialdialogs.utils.MDUtil.resolveString 27 | 28 | /** @author Aidan Follestad (@afollestad) */ 29 | class DialogMessageSettings internal constructor( 30 | private val dialog: MaterialDialog, 31 | @Suppress("MemberVisibilityCanBePrivate") 32 | val messageTextView: TextView 33 | ) { 34 | private var isHtml: Boolean = false 35 | private var didSetLineSpacing: Boolean = false 36 | 37 | fun lineSpacing(multiplier: Float): DialogMessageSettings { 38 | didSetLineSpacing = true 39 | messageTextView.setLineSpacing(0f, multiplier) 40 | return this 41 | } 42 | 43 | fun html(onLinkClick: ((link: String) -> Unit)? = null): DialogMessageSettings { 44 | isHtml = true 45 | if (onLinkClick != null) { 46 | messageTextView.transformationMethod = LinkTransformationMethod(onLinkClick) 47 | } 48 | messageTextView.movementMethod = LinkMovementMethod.getInstance() 49 | return this 50 | } 51 | 52 | internal fun setText( 53 | @StringRes res: Int?, 54 | text: CharSequence? 55 | ) { 56 | if (!didSetLineSpacing) { 57 | lineSpacing( 58 | resolveFloat( 59 | context = dialog.windowContext, 60 | attr = R.attr.md_line_spacing_body, 61 | defaultValue = 1.1f 62 | ) 63 | ) 64 | } 65 | messageTextView.text = text.maybeWrapHtml(isHtml) 66 | ?: resolveString(dialog, res, html = isHtml) 67 | } 68 | 69 | private fun CharSequence?.maybeWrapHtml(isHtml: Boolean): CharSequence? { 70 | if (this == null) return null 71 | @Suppress("DEPRECATION") 72 | return if (isHtml) Html.fromHtml(this.toString()) else this 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/utils/Arrays.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.utils 17 | 18 | internal inline fun List.pullIndices(indices: IntArray): List { 19 | return mutableListOf().apply { 20 | for (index in indices) { 21 | add(this@pullIndices[index]) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/utils/Colors.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.utils 17 | 18 | import android.graphics.Color 19 | import androidx.annotation.AttrRes 20 | import androidx.annotation.CheckResult 21 | import androidx.annotation.ColorInt 22 | import androidx.annotation.ColorRes 23 | import com.afollestad.materialdialogs.MaterialDialog 24 | import com.afollestad.materialdialogs.utils.MDUtil.resolveColor 25 | import com.afollestad.materialdialogs.utils.MDUtil.resolveColors 26 | 27 | @ColorInt @CheckResult 28 | internal fun MaterialDialog.resolveColor( 29 | @ColorRes res: Int? = null, 30 | @AttrRes attr: Int? = null, 31 | fallback: (() -> Int)? = null 32 | ): Int = resolveColor(windowContext, res, attr, fallback) 33 | 34 | @CheckResult 35 | internal fun MaterialDialog.resolveColors( 36 | attrs: IntArray, 37 | fallback: ((forAttr: Int) -> Int)? = null 38 | ) = resolveColors(windowContext, attrs, fallback) 39 | 40 | @ColorInt @CheckResult 41 | internal fun Int.adjustAlpha(alpha: Float): Int { 42 | return Color.argb((255 * alpha).toInt(), Color.red(this), Color.green(this), Color.blue(this)) 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/utils/Dimens.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.utils 17 | 18 | import android.util.TypedValue 19 | import android.util.TypedValue.COMPLEX_UNIT_DIP 20 | import android.view.View 21 | import androidx.annotation.AttrRes 22 | import androidx.annotation.DimenRes 23 | import com.afollestad.materialdialogs.MaterialDialog 24 | import com.afollestad.materialdialogs.utils.MDUtil.assertOneSet 25 | 26 | internal fun MaterialDialog.dimen( 27 | @DimenRes res: Int? = null, 28 | @AttrRes attr: Int? = null, 29 | fallback: Float = 0f 30 | ): Float { 31 | assertOneSet("dimen", attr, res) 32 | if (res != null) { 33 | return windowContext.resources.getDimension(res) 34 | } 35 | requireNotNull(attr) 36 | val a = windowContext.theme.obtainStyledAttributes(intArrayOf(attr)) 37 | try { 38 | return a.getDimension(0, fallback) 39 | } finally { 40 | a.recycle() 41 | } 42 | } 43 | 44 | internal fun View.dp(value: Int): Float { 45 | return TypedValue.applyDimension(COMPLEX_UNIT_DIP, value.toFloat(), resources.displayMetrics) 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/utils/Fonts.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.utils 17 | 18 | import android.content.Context 19 | import android.graphics.Typeface 20 | import androidx.annotation.AttrRes 21 | import androidx.annotation.CheckResult 22 | import androidx.annotation.FontRes 23 | import androidx.core.content.res.ResourcesCompat 24 | import com.afollestad.materialdialogs.MaterialDialog 25 | import com.afollestad.materialdialogs.utils.MDUtil.assertOneSet 26 | 27 | @CheckResult internal fun MaterialDialog.font( 28 | @FontRes res: Int? = null, 29 | @AttrRes attr: Int? = null 30 | ): Typeface? { 31 | assertOneSet("font", attr, res) 32 | if (res != null) { 33 | return safeGetFont(windowContext, res) 34 | } 35 | requireNotNull(attr) 36 | val a = windowContext.theme.obtainStyledAttributes(intArrayOf(attr)) 37 | try { 38 | val resId = a.getResourceId(0, 0) 39 | if (resId == 0) return null 40 | return safeGetFont(windowContext, resId) 41 | } finally { 42 | a.recycle() 43 | } 44 | } 45 | 46 | private fun safeGetFont(context: Context, @FontRes res: Int): Typeface? { 47 | return try { 48 | ResourcesCompat.getFont(context, res) 49 | } catch (e: Throwable) { 50 | e.printStackTrace() 51 | null 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/utils/IntArrays.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.utils 17 | 18 | internal fun IntArray.appendAll(values: Collection): IntArray { 19 | return toMutableList() 20 | .apply { addAll(values) } 21 | .toIntArray() 22 | } 23 | 24 | internal fun IntArray.removeAll(values: Collection): IntArray { 25 | return toMutableList().apply { removeAll { values.contains(it) } } 26 | .toIntArray() 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/com/afollestad/materialdialogs/utils/Views.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.utils 17 | 18 | import android.os.Build.VERSION.SDK_INT 19 | import android.os.Build.VERSION_CODES.JELLY_BEAN_MR1 20 | import android.view.Gravity 21 | import android.view.LayoutInflater 22 | import android.view.View 23 | import android.view.ViewGroup 24 | import android.widget.Button 25 | import android.widget.TextView 26 | import androidx.annotation.LayoutRes 27 | import com.afollestad.materialdialogs.MaterialDialog 28 | 29 | @Suppress("UNCHECKED_CAST") 30 | internal fun MaterialDialog.inflate( 31 | @LayoutRes res: Int, 32 | root: ViewGroup? = null 33 | ) = LayoutInflater.from(windowContext).inflate(res, root, false) as T 34 | 35 | @Suppress("UNCHECKED_CAST") 36 | internal fun ViewGroup.inflate( 37 | @LayoutRes res: Int, 38 | root: ViewGroup? = this 39 | ) = LayoutInflater.from(context).inflate(res, root, false) as T 40 | 41 | internal fun T.isVisible(): Boolean { 42 | return if (this is Button) { 43 | this.visibility == View.VISIBLE && this.text.trim().isNotBlank() 44 | } else { 45 | this.visibility == View.VISIBLE 46 | } 47 | } 48 | 49 | internal fun T.isNotVisible(): Boolean = !isVisible() 50 | 51 | internal fun T.isRtl(): Boolean { 52 | return if (SDK_INT < JELLY_BEAN_MR1) false else resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL 53 | } 54 | 55 | internal fun TextView.setGravityStartCompat() { 56 | if (SDK_INT >= JELLY_BEAN_MR1) { 57 | this.textAlignment = View.TEXT_ALIGNMENT_VIEW_START 58 | } 59 | this.gravity = Gravity.START or Gravity.CENTER_VERTICAL 60 | } 61 | 62 | internal fun TextView.setGravityEndCompat() { 63 | if (SDK_INT >= JELLY_BEAN_MR1) { 64 | this.textAlignment = View.TEXT_ALIGNMENT_VIEW_END 65 | } 66 | this.gravity = Gravity.END or Gravity.CENTER_VERTICAL 67 | } 68 | -------------------------------------------------------------------------------- /core/src/main/res-public/values/public.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /core/src/main/res/anim/decelerate_cubic.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /core/src/main/res/anim/popup_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/anim/popup_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/color/md_list_item_textcolor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /core/src/main/res/drawable-v21/md_btn_selector.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /core/src/main/res/drawable-v21/md_btn_selector_dark.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /core/src/main/res/drawable-v21/md_btn_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /core/src/main/res/drawable-v21/md_item_selector.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /core/src/main/res/drawable-v21/md_item_selector_dark.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /core/src/main/res/drawable-v21/md_item_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/md_btn_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/md_btn_selected_dark.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/md_btn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/md_btn_selector_dark.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/md_item_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/md_item_selected_dark.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/md_item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/md_item_selector_dark.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/md_nav_back.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/res/drawable/md_transparent.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /core/src/main/res/layout/md_dialog_base.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /core/src/main/res/layout/md_dialog_stub_buttons.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 22 | 23 | 28 | 29 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /core/src/main/res/layout/md_dialog_stub_message.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /core/src/main/res/layout/md_dialog_stub_recyclerview.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | -------------------------------------------------------------------------------- /core/src/main/res/layout/md_dialog_stub_scrollview.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /core/src/main/res/layout/md_dialog_stub_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /core/src/main/res/layout/md_listitem.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /core/src/main/res/layout/md_listitem_multichoice.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /core/src/main/res/layout/md_listitem_singlechoice.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /core/src/main/res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 446dp 5 | 6 | 7 | -------------------------------------------------------------------------------- /core/src/main/res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 564dp 5 | 6 | 7 | -------------------------------------------------------------------------------- /core/src/main/res/values-sw720dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 496dp 5 | 6 | -------------------------------------------------------------------------------- /core/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /core/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #33969696 5 | #40CBCBCB 6 | 7 | #E0E0E0 8 | #3B3C3F 9 | 10 | #818181 11 | #C2C2C2 12 | 13 | 14 | -------------------------------------------------------------------------------- /core/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 356dp 5 | 4dp 6 | 52dp 7 | 32dp 8 | 9 | 20dp 10 | 24dp 11 | 16dp 12 | 24dp 13 | 14 | 52dp 15 | 7dp 16 | 8dp 17 | 8dp 18 | 4dp 19 | 12dp 20 | 4dp 21 | 22 | 64dp 23 | 2dp 24 | 14sp 25 | 26 | 48dp 27 | 28 | 20sp 29 | 16sp 30 | 31 | 16dp 32 | 42dp 33 | 34 | 12dp 35 | 8dp 36 | 16sp 37 | 48dp 38 | 6dp 39 | 24dp 40 | 0dp 41 | 42 | 16dp 43 | 4dp 44 | 1dp 45 | 46 | 47 | -------------------------------------------------------------------------------- /datetime/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /datetime/build.gradle: -------------------------------------------------------------------------------- 1 | ext.module_group = "com.afollestad.material-dialogs" 2 | ext.module_name = "datetime" 3 | 4 | apply from: rootProject.file("gradle/android_library_config.gradle") 5 | 6 | dependencies { 7 | api project(':core') 8 | api deps.afollestad.date_picker 9 | compileOnly deps.androidx.annotations 10 | 11 | implementation deps.afollestad.dots_indicator 12 | implementation deps.kotlin.stdlib8 13 | } 14 | -------------------------------------------------------------------------------- /datetime/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /datetime/src/main/java/com/afollestad/materialdialogs/datetime/DatePickerExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | @file:Suppress("unused") 17 | 18 | package com.afollestad.materialdialogs.datetime 19 | 20 | import android.R.string 21 | import androidx.annotation.CheckResult 22 | import com.afollestad.materialdialogs.MaterialDialog 23 | import com.afollestad.materialdialogs.WhichButton.POSITIVE 24 | import com.afollestad.materialdialogs.actions.setActionButtonEnabled 25 | import com.afollestad.materialdialogs.callbacks.onDismiss 26 | import com.afollestad.materialdialogs.customview.customView 27 | import com.afollestad.materialdialogs.datetime.internal.TimeChangeListener 28 | import com.afollestad.materialdialogs.datetime.utils.getDatePicker 29 | import com.afollestad.materialdialogs.datetime.utils.isFutureDate 30 | import com.afollestad.materialdialogs.utils.MDUtil.isLandscape 31 | import java.util.Calendar 32 | 33 | /** 34 | * Makes the dialog a date picker. 35 | */ 36 | fun MaterialDialog.datePicker( 37 | minDate: Calendar? = null, 38 | maxDate: Calendar? = null, 39 | currentDate: Calendar? = null, 40 | requireFutureDate: Boolean = false, 41 | dateCallback: DateTimeCallback = null 42 | ): MaterialDialog { 43 | customView( 44 | R.layout.md_datetime_picker_date, 45 | noVerticalPadding = true, 46 | dialogWrapContent = windowContext.isLandscape() 47 | ) 48 | 49 | check(minDate == null || currentDate == null || minDate.before(currentDate)) { 50 | "Your `minDate` must be less than `currentDate`." 51 | } 52 | check(maxDate == null || currentDate == null || maxDate.after(currentDate)) { 53 | "Your `maxDate` must be bigger than `currentDate`." 54 | } 55 | 56 | getDatePicker().apply { 57 | minDate?.let { setMinDate(it) } 58 | maxDate?.let { setMaxDate(it) } 59 | currentDate?.let { setDate(it) } 60 | 61 | addOnDateChanged { _, _ -> 62 | val isFutureDate = getDatePicker().isFutureDate() 63 | setActionButtonEnabled( 64 | POSITIVE, 65 | !requireFutureDate || isFutureDate 66 | ) 67 | } 68 | } 69 | 70 | positiveButton(string.ok) { 71 | getDatePicker().getDate()?.let { datetime -> 72 | dateCallback?.invoke(it, datetime) 73 | } 74 | } 75 | negativeButton(string.cancel) 76 | 77 | if (requireFutureDate) { 78 | val changeListener = TimeChangeListener(windowContext, getDatePicker()) { 79 | val isFutureDate = it.isFutureDate() 80 | setActionButtonEnabled( 81 | POSITIVE, 82 | !requireFutureDate || isFutureDate 83 | ) 84 | } 85 | onDismiss { changeListener.dispose() } 86 | } 87 | 88 | return this 89 | } 90 | 91 | /** 92 | * Gets the currently selected date from a date picker dialog. 93 | */ 94 | @CheckResult fun MaterialDialog.selectedDate(): Calendar { 95 | return getDatePicker().getDate()!! 96 | } 97 | -------------------------------------------------------------------------------- /datetime/src/main/java/com/afollestad/materialdialogs/datetime/TimePickerExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | @file:Suppress("unused") 17 | 18 | package com.afollestad.materialdialogs.datetime 19 | 20 | import androidx.annotation.CheckResult 21 | import com.afollestad.materialdialogs.MaterialDialog 22 | import com.afollestad.materialdialogs.WhichButton.POSITIVE 23 | import com.afollestad.materialdialogs.actions.setActionButtonEnabled 24 | import com.afollestad.materialdialogs.callbacks.onDismiss 25 | import com.afollestad.materialdialogs.customview.customView 26 | import com.afollestad.materialdialogs.datetime.internal.TimeChangeListener 27 | import com.afollestad.materialdialogs.datetime.utils.getTimePicker 28 | import com.afollestad.materialdialogs.datetime.utils.hour 29 | import com.afollestad.materialdialogs.datetime.utils.isFutureTime 30 | import com.afollestad.materialdialogs.datetime.utils.minute 31 | import com.afollestad.materialdialogs.datetime.utils.toCalendar 32 | import com.afollestad.materialdialogs.utils.MDUtil.isLandscape 33 | import java.util.Calendar 34 | 35 | /** 36 | * Makes the dialog a time picker. 37 | */ 38 | fun MaterialDialog.timePicker( 39 | currentTime: Calendar? = null, 40 | requireFutureTime: Boolean = false, 41 | show24HoursView: Boolean = true, 42 | timeCallback: DateTimeCallback = null 43 | ): MaterialDialog { 44 | customView( 45 | R.layout.md_datetime_picker_time, 46 | noVerticalPadding = true, 47 | dialogWrapContent = windowContext.isLandscape() 48 | ) 49 | 50 | with(getTimePicker()) { 51 | setIs24HourView(show24HoursView) 52 | if (currentTime != null) { 53 | hour(currentTime.get(Calendar.HOUR_OF_DAY)) 54 | minute(currentTime.get(Calendar.MINUTE)) 55 | } 56 | setOnTimeChangedListener { _, _, _ -> 57 | val isFutureTime = isFutureTime() 58 | setActionButtonEnabled( 59 | POSITIVE, 60 | !requireFutureTime || isFutureTime 61 | ) 62 | } 63 | } 64 | 65 | positiveButton(android.R.string.ok) { 66 | timeCallback?.invoke(it, getTimePicker().toCalendar()) 67 | } 68 | negativeButton(android.R.string.cancel) 69 | 70 | if (requireFutureTime) { 71 | val changeListener = TimeChangeListener(windowContext, getTimePicker()) { 72 | val isFutureTime = it.isFutureTime() 73 | setActionButtonEnabled( 74 | POSITIVE, 75 | !requireFutureTime || isFutureTime 76 | ) 77 | } 78 | onDismiss { changeListener.dispose() } 79 | } 80 | 81 | return this 82 | } 83 | 84 | /** 85 | * Gets the currently selected time from a time picker dialog. 86 | */ 87 | @CheckResult fun MaterialDialog.selectedTime(): Calendar { 88 | return getTimePicker().toCalendar() 89 | } 90 | -------------------------------------------------------------------------------- /datetime/src/main/java/com/afollestad/materialdialogs/datetime/internal/DateTimePickerAdapter.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.datetime.internal 17 | 18 | import android.view.View 19 | import android.view.ViewGroup 20 | import androidx.viewpager.widget.PagerAdapter 21 | import com.afollestad.materialdialogs.datetime.R.id 22 | 23 | internal class DateTimePickerAdapter : PagerAdapter() { 24 | 25 | override fun instantiateItem( 26 | container: ViewGroup, 27 | position: Int 28 | ): Any { 29 | val resId = when (position) { 30 | 0 -> id.datetimeDatePicker 31 | 1 -> id.datetimeTimePicker 32 | else -> throw IllegalStateException("Unexpected position: $position") 33 | } 34 | return container.findViewById(resId) 35 | } 36 | 37 | override fun getCount(): Int = 2 38 | 39 | override fun isViewFromObject( 40 | view: View, 41 | `object`: Any 42 | ): Boolean = view === `object` as View 43 | 44 | override fun destroyItem( 45 | container: ViewGroup, 46 | position: Int, 47 | `object`: Any 48 | ) = Unit 49 | } 50 | -------------------------------------------------------------------------------- /datetime/src/main/java/com/afollestad/materialdialogs/datetime/internal/TimeChangeListener.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.datetime.internal 17 | 18 | import android.content.BroadcastReceiver 19 | import android.content.Context 20 | import android.content.Intent 21 | import android.content.IntentFilter 22 | import java.util.Calendar 23 | 24 | /** @author Aidan Follestad (@afollestad) */ 25 | internal class TimeChangeListener( 26 | private var context: Context?, 27 | private val argument: T?, 28 | private var onChange: ((arg: T) -> Unit)? = null 29 | ) { 30 | private var lastHour: Int = -1 31 | private var lastMinute: Int = -1 32 | 33 | private val receiver = object : BroadcastReceiver() { 34 | override fun onReceive( 35 | context: Context?, 36 | intent: Intent? 37 | ) { 38 | val now = Calendar.getInstance() 39 | val newHour = now.get(Calendar.HOUR_OF_DAY) 40 | val newMinute = now.get(Calendar.MINUTE) 41 | 42 | if (argument != null && (lastHour != newHour || lastMinute != newMinute)) { 43 | onChange?.invoke(argument) 44 | lastHour = newHour 45 | lastMinute = newMinute 46 | } 47 | } 48 | } 49 | 50 | init { 51 | requireNotNull(context) 52 | requireNotNull(argument) 53 | requireNotNull(onChange) 54 | 55 | val filter = IntentFilter().apply { 56 | addAction(Intent.ACTION_TIME_TICK) 57 | addAction(Intent.ACTION_TIMEZONE_CHANGED) 58 | addAction(Intent.ACTION_TIME_CHANGED) 59 | } 60 | context!!.registerReceiver(receiver, filter) 61 | } 62 | 63 | fun dispose() { 64 | context?.unregisterReceiver(receiver) 65 | context = null 66 | onChange = null 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /datetime/src/main/java/com/afollestad/materialdialogs/datetime/internal/WrapContentViewPager.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.datetime.internal 17 | 18 | import android.content.Context 19 | import android.util.AttributeSet 20 | import android.view.View 21 | import android.view.View.MeasureSpec.EXACTLY 22 | import android.view.View.MeasureSpec.UNSPECIFIED 23 | import androidx.viewpager.widget.ViewPager 24 | import com.afollestad.materialdialogs.utils.MDUtil.ifNotZero 25 | 26 | internal class WrapContentViewPager( 27 | context: Context, 28 | attrs: AttributeSet? = null 29 | ) : ViewPager(context, attrs) { 30 | 31 | override fun onMeasure( 32 | widthMeasureSpec: Int, 33 | heightMeasureSpec: Int 34 | ) { 35 | var newHeightSpec = heightMeasureSpec 36 | 37 | var maxChildHeight = 0 38 | forEachChild { child -> 39 | child.measure( 40 | widthMeasureSpec, 41 | MeasureSpec.makeMeasureSpec(0, UNSPECIFIED) 42 | ) 43 | 44 | val h = child.measuredHeight 45 | if (h > maxChildHeight) { 46 | maxChildHeight = h 47 | } 48 | } 49 | 50 | val maxAllowedHeightFromParent = MeasureSpec.getSize(heightMeasureSpec) 51 | if (maxChildHeight > maxAllowedHeightFromParent) { 52 | maxChildHeight = maxAllowedHeightFromParent 53 | } 54 | maxChildHeight.ifNotZero { 55 | newHeightSpec = MeasureSpec.makeMeasureSpec(it, EXACTLY) 56 | } 57 | 58 | super.onMeasure(widthMeasureSpec, newHeightSpec) 59 | } 60 | 61 | private fun forEachChild(each: (View) -> Unit) { 62 | for (i in 0 until childCount) { 63 | val child = getChildAt(i) 64 | each(child) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /datetime/src/main/java/com/afollestad/materialdialogs/datetime/utils/DateTimeExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.datetime.utils 17 | 18 | import android.widget.TimePicker 19 | import com.afollestad.date.DatePicker 20 | import java.util.Calendar 21 | import java.util.GregorianCalendar 22 | 23 | internal fun isFutureTime( 24 | datePicker: DatePicker, 25 | timePicker: TimePicker 26 | ): Boolean { 27 | val now = Calendar.getInstance() 28 | val dateTime = toCalendar(datePicker, timePicker) 29 | return dateTime.timeInMillis >= now.timeInMillis 30 | } 31 | 32 | internal fun TimePicker.isFutureTime(): Boolean { 33 | val now = Calendar.getInstance() 34 | return toCalendar().timeInMillis >= now.timeInMillis 35 | } 36 | 37 | internal fun DatePicker.isFutureDate(): Boolean { 38 | val now = Calendar.getInstance() 39 | return getDate()!!.timeInMillis >= now.timeInMillis 40 | } 41 | 42 | internal fun TimePicker.toCalendar(): Calendar { 43 | val now = Calendar.getInstance() 44 | return GregorianCalendar( 45 | now.get(Calendar.YEAR), 46 | now.get(Calendar.MONTH), 47 | now.get(Calendar.DAY_OF_MONTH), 48 | hour(), 49 | minute() 50 | ) 51 | } 52 | 53 | internal fun toCalendar( 54 | datePicker: DatePicker, 55 | timePicker: TimePicker 56 | ): Calendar { 57 | return datePicker.getDate()!!.apply { 58 | set(Calendar.HOUR_OF_DAY, timePicker.hour()) 59 | set(Calendar.MINUTE, timePicker.minute()) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /datetime/src/main/java/com/afollestad/materialdialogs/datetime/utils/ViewExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | @file:Suppress("DEPRECATION") 17 | 18 | package com.afollestad.materialdialogs.datetime.utils 19 | 20 | import android.os.Build 21 | import android.widget.TimePicker 22 | import androidx.viewpager.widget.ViewPager 23 | import com.afollestad.date.DatePicker 24 | import com.afollestad.materialdialogs.MaterialDialog 25 | import com.afollestad.materialdialogs.datetime.R 26 | import com.afollestad.viewpagerdots.DotsIndicator 27 | 28 | internal fun TimePicker.hour(): Int = if (isNougat()) hour else currentHour 29 | 30 | internal fun TimePicker.minute(): Int = if (isNougat()) minute else currentMinute 31 | 32 | internal fun TimePicker.hour(value: Int) { 33 | if (isNougat()) hour = value else currentHour = value 34 | } 35 | 36 | internal fun TimePicker.minute(value: Int) { 37 | if (isNougat()) minute = value else currentMinute = value 38 | } 39 | 40 | internal fun MaterialDialog.getDatePicker() = findViewById(R.id.datetimeDatePicker) 41 | 42 | internal fun MaterialDialog.getTimePicker() = findViewById(R.id.datetimeTimePicker) 43 | 44 | internal fun MaterialDialog.getPager() = findViewById(R.id.dateTimePickerPager) 45 | 46 | internal fun MaterialDialog.getPageIndicator() = 47 | findViewById(R.id.datetimePickerPagerDots) 48 | 49 | private fun isNougat() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N 50 | -------------------------------------------------------------------------------- /datetime/src/main/res-public/values/public.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /datetime/src/main/res/layout/md_datetime_picker_date.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | -------------------------------------------------------------------------------- /datetime/src/main/res/layout/md_datetime_picker_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /datetime/src/main/res/layout/md_datetime_picker_time.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /datetime/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24dp 4 | 8dp 5 | -------------------------------------------------------------------------------- /dependencies.gradle: -------------------------------------------------------------------------------- 1 | ext.versions = [ 2 | min_sdk: 16, 3 | compile_sdk: 29, 4 | build_tools: "29.0.0", 5 | publish_version: "3.3.0", 6 | publish_version_code: 262 7 | ] 8 | 9 | ext.deps = [ 10 | gradle_plugins: [ 11 | android: "com.android.tools.build:gradle:4.1.2", 12 | kotlin: "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61", 13 | spotless: "com.diffplug.spotless:spotless-plugin-gradle:3.27.1", 14 | versions: "com.github.ben-manes:gradle-versions-plugin:0.27.0" 15 | ], 16 | 17 | androidx: [ 18 | annotations: "androidx.annotation:annotation:1.1.0", 19 | core: "androidx.appcompat:appcompat:1.1.0", 20 | grid_layout: "androidx.gridlayout:gridlayout:1.0.0", 21 | lifecycle: [ 22 | runtime: "androidx.lifecycle:lifecycle-runtime:2.2.0", 23 | compiler: "androidx.lifecycle:lifecycle-compiler:2.2.0" 24 | ], 25 | recycler_view: "androidx.recyclerview:recyclerview:1.1.0" 26 | ], 27 | 28 | google_material: "com.google.android.material:material:1.1.0", 29 | 30 | kotlin: [ 31 | stdlib8: "org.jetbrains.kotlin:kotlin-stdlib-jdk8", 32 | coroutines: [ 33 | android: "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2" 34 | ] 35 | ], 36 | 37 | afollestad: [ 38 | assent: "com.afollestad:assent:2.3.1", 39 | dots_indicator: "com.afollestad:viewpagerdots:1.0.0", 40 | date_picker: "com.afollestad:date-picker:0.6.1" 41 | ], 42 | 43 | leak_canary: "com.squareup.leakcanary:leakcanary-android:2.2" 44 | ] 45 | -------------------------------------------------------------------------------- /documentation/COLOR.md: -------------------------------------------------------------------------------- 1 | # Color 2 | 3 | # Table of Contents - Color 4 | 5 | 1. [Gradle Dependency](#gradle-dependency) 6 | 2. [Color Choosers](#color-choosers) 7 | 1. [Basics](#basics) 8 | 2. [Sub Colors](#sub-colors) 9 | 10 | ## Gradle Dependency 11 | 12 | [ ![Color](https://img.shields.io/maven-central/v/com.afollestad.material-dialogs/color?label=color&style=for-the-badge) ](https://repo1.maven.org/maven2/com/afollestad/material-dialogs/color) 13 | 14 | The `color` module contains extensions to the core module, such as a color chooser. 15 | 16 | ```gradle 17 | dependencies { 18 | ... 19 | implementation 'com.afollestad.material-dialogs:color:3.2.1' 20 | } 21 | ``` 22 | 23 | ## Color Choosers 24 | 25 | ### Basics 26 | 27 | Color choosers show a simple grid of colors. 28 | 29 | 30 | 31 | ```kotlin 32 | val colors = intArrayOf(RED, GREEN, BLUE) 33 | 34 | MaterialDialog(this).show { 35 | title(R.string.colors) 36 | colorChooser(colors) { dialog, color -> 37 | // Use color integer 38 | } 39 | positiveButton(R.string.select) 40 | } 41 | ``` 42 | 43 | You can specify an initial selection, which is just a color integer: 44 | 45 | ```kotlin 46 | val colors = intArrayOf(RED, GREEN, BLUE) 47 | 48 | MaterialDialog(this).show { 49 | title(R.string.colors) 50 | colorChooser(colors, initialSelection = BLUE) { dialog, color -> 51 | // Use color integer 52 | } 53 | positiveButton(R.string.select) 54 | } 55 | ``` 56 | 57 | ### Sub Colors 58 | 59 | You can specify sub-colors, which are a level down from each top level color. The size of the top 60 | level array must match the size of the sub-colors array. 61 | 62 | 63 | 64 | ```kotlin 65 | val colors = intArrayOf(RED, GREEN, BLUE) // size = 3 66 | 67 | val subColors = listOf( // size = 3 68 | intArrayOf(LIGHT_RED, RED, DARK_RED, WHITE), 69 | intArrayOf(LIGHT_GREEN, GREEN, DARK_GREEN, GRAY), 70 | intArrayOf(LIGHT_BLUE, BLUE, DARK_BLUE, BLACK) 71 | ) 72 | 73 | MaterialDialog(this).show { 74 | title(R.string.colors) 75 | colorChooser(colors, subColors = subColors) { dialog, color -> 76 | // Use color integer 77 | } 78 | positiveButton(R.string.select) 79 | } 80 | ``` 81 | 82 | ### ARGB Selection 83 | 84 | 85 | 86 | ```kotlin 87 | MaterialDialog(this).show { 88 | title(R.string.colors) 89 | colorChooser( 90 | colors = colors, 91 | subColors = subColors, 92 | allowCustomArgb = true, 93 | showAlphaSelector = true 94 | ) { dialog, color -> 95 | // Use color integer 96 | } 97 | positiveButton(R.string.select) 98 | } 99 | ``` 100 | 101 | Omitting `showAlphaSelector` will hide the alpha (transparency) selector. 102 | -------------------------------------------------------------------------------- /documentation/DATETIME.md: -------------------------------------------------------------------------------- 1 | # DateTime 2 | 3 | ## Table of Contents 4 | 5 | 1. [Gradle Dependency](#gradle-dependency-4) 6 | 2. [Date](#date) 7 | 3. [Time](#time) 8 | 4. [DateTime](#datetime) 9 | 10 | ## Gradle Dependency 11 | 12 | [ ![DateTime](https://img.shields.io/maven-central/v/com.afollestad.material-dialogs/datetime?label=datetime&style=for-the-badge) ](https://repo1.maven.org/maven2/com/afollestad/material-dialogs/datetime) 13 | 14 | The `datetime` module contains extensions to make date, time, and date-time picker dialogs. 15 | 16 | ```gradle 17 | dependencies { 18 | ... 19 | implementation 'com.afollestad.material-dialogs:datetime:3.2.1' 20 | } 21 | ``` 22 | 23 | ## Date 24 | 25 | 26 | 27 | ```kotlin 28 | MaterialDialog(this).show { 29 | ... 30 | datePicker { dialog, date -> 31 | // Use date (Calendar) 32 | } 33 | } 34 | ``` 35 | 36 | You can optionally provide `minDate`, `maxDate` and `currentDate` parameters as well. 37 | 38 | ## Time 39 | 40 | 41 | 42 | ```kotlin 43 | MaterialDialog(this).show { 44 | ... 45 | timePicker { dialog, time -> 46 | // Use time (Calendar) 47 | } 48 | } 49 | ``` 50 | 51 | You can optionally provide `currentTime` and `show24HoursView` parameters as well. 52 | 53 | ## DateTime 54 | 55 | 56 | 57 | ```kotlin 58 | MaterialDialog(this).show { 59 | ... 60 | dateTimePicker(requireFutureDateTime = true) { _, dateTime -> 61 | // Use dateTime (Calendar) 62 | } 63 | } 64 | ``` 65 | 66 | You can optionally provide `minDateTime`, `maxDate`, `currentDateTime`, `show24HoursView`, 67 | and `requireFutureDateTime` parameters as well. 68 | -------------------------------------------------------------------------------- /documentation/LIFECYCLE.md: -------------------------------------------------------------------------------- 1 | # Lifecycle 2 | 3 | ## Table of Contents 4 | 5 | 1. [Gradle Dependency](#gradle-dependency) 6 | 2. [Usage](#usage) 7 | 8 | 9 | ## Gradle Dependency 10 | 11 | [ ![Lifecycle](https://img.shields.io/maven-central/v/com.afollestad.material-dialogs/lifecycle?label=lifecycle&style=for-the-badge) ](https://repo1.maven.org/maven2/com/afollestad/material-dialogs/lifecycle) 12 | 13 | The `lifecycle` module contains extensions to make dialogs work with AndroidX lifecycles. 14 | 15 | ```gradle 16 | dependencies { 17 | ... 18 | implementation 'com.afollestad.material-dialogs:lifecycle:3.2.1' 19 | } 20 | ``` 21 | 22 | ## Usage 23 | 24 | ```kotlin 25 | MaterialDialog(this).show { 26 | ... 27 | lifecycleOwner(owner) 28 | } 29 | ``` 30 | 31 | When the given lifecycle owner is destroyed, the dialog is automatically dismissed. Lifecycle 32 | owners include Activities and Fragments from AndroidX, along with any class that implements the 33 | `LifecycleOwner` interface. 34 | -------------------------------------------------------------------------------- /files/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /files/build.gradle: -------------------------------------------------------------------------------- 1 | ext.module_group = "com.afollestad.material-dialogs" 2 | ext.module_name = "files" 3 | 4 | apply from: rootProject.file("gradle/android_library_config.gradle") 5 | 6 | dependencies { 7 | api project(':core') 8 | api project(':input') 9 | 10 | implementation deps.kotlin.coroutines.android 11 | implementation deps.kotlin.stdlib8 12 | } 13 | -------------------------------------------------------------------------------- /files/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /files/src/main/java/com/afollestad/materialdialogs/files/util/ContextExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.files.util 17 | 18 | import android.content.Context 19 | import java.io.File 20 | 21 | internal fun Context.getExternalFilesDir(): File? { 22 | return this.getExternalFilesDir(null) 23 | } 24 | -------------------------------------------------------------------------------- /files/src/main/java/com/afollestad/materialdialogs/files/util/FilesUtilExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | @file:Suppress("SpellCheckingInspection") 17 | 18 | package com.afollestad.materialdialogs.files.util 19 | 20 | import android.Manifest.permission 21 | import android.content.Context 22 | import android.content.pm.PackageManager 23 | import androidx.core.content.ContextCompat 24 | import com.afollestad.materialdialogs.MaterialDialog 25 | import com.afollestad.materialdialogs.files.FileFilter 26 | import java.io.File 27 | 28 | internal fun File.hasParent( 29 | context: Context, 30 | writeable: Boolean, 31 | filter: FileFilter 32 | ) = betterParent(context, writeable, filter) != null 33 | 34 | internal fun File.isExternalStorage(context: Context) = 35 | absolutePath == context.getExternalFilesDir()?.absolutePath 36 | 37 | internal fun File.isRoot() = absolutePath == "/" 38 | 39 | internal fun File.betterParent( 40 | context: Context, 41 | writeable: Boolean, 42 | filter: FileFilter 43 | ): File? { 44 | val parentToUse = (if (isExternalStorage(context)) { 45 | // Emulated external storage's parent is empty so jump over it 46 | context.getExternalFilesDir()?.parentFile?.parentFile 47 | } else { 48 | parentFile 49 | }) ?: return null 50 | 51 | if ((writeable && !parentToUse.canWrite()) || !parentToUse.canRead()) { 52 | // We can't access this folder 53 | return null 54 | } 55 | 56 | val folderContent = 57 | parentToUse.listFiles()?.filter { filter?.invoke(it) ?: true } ?: emptyList() 58 | if (folderContent.isEmpty()) { 59 | // There is nothing in this folder most likely because we can't access files inside of it. 60 | // We don't want to get stuck here. 61 | return null 62 | } 63 | 64 | return parentToUse 65 | } 66 | 67 | internal fun File.jumpOverEmulated(context: Context): File { 68 | val externalFileDir = context.getExternalFilesDir() 69 | externalFileDir?.parentFile?.let { externalParentFile -> 70 | if (absolutePath == externalParentFile.absolutePath) { 71 | return externalFileDir 72 | } 73 | } 74 | return this 75 | } 76 | 77 | internal fun File.friendlyName(context: Context) = when { 78 | isExternalStorage(context) -> "External Storage" 79 | isRoot() -> "Root" 80 | else -> name 81 | } 82 | 83 | internal fun Context.hasPermission(permission: String): Boolean { 84 | return ContextCompat.checkSelfPermission(this, permission) == 85 | PackageManager.PERMISSION_GRANTED 86 | } 87 | 88 | internal fun MaterialDialog.hasReadStoragePermission(): Boolean { 89 | return windowContext.hasPermission(permission.READ_EXTERNAL_STORAGE) 90 | } 91 | 92 | internal fun MaterialDialog.hasWriteStoragePermission(): Boolean { 93 | return windowContext.hasPermission(permission.WRITE_EXTERNAL_STORAGE) 94 | } 95 | -------------------------------------------------------------------------------- /files/src/main/java/com/afollestad/materialdialogs/files/util/ViewExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.files.util 17 | 18 | import android.view.View 19 | 20 | internal fun T.setVisible(visible: Boolean) { 21 | visibility = if (visible) View.VISIBLE else View.INVISIBLE 22 | } 23 | -------------------------------------------------------------------------------- /files/src/main/res-public/values/public.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /files/src/main/res/drawable/icon_file_dark.xml: -------------------------------------------------------------------------------- 1 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /files/src/main/res/drawable/icon_file_light.xml: -------------------------------------------------------------------------------- 1 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /files/src/main/res/drawable/icon_folder_dark.xml: -------------------------------------------------------------------------------- 1 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /files/src/main/res/drawable/icon_folder_light.xml: -------------------------------------------------------------------------------- 1 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /files/src/main/res/drawable/icon_new_folder_dark.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /files/src/main/res/drawable/icon_new_folder_light.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /files/src/main/res/drawable/icon_return_dark.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /files/src/main/res/drawable/icon_return_light.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /files/src/main/res/layout/md_file_chooser_base.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /files/src/main/res/layout/md_file_chooser_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 26 | 27 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /files/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18sp 4 | 32dp 5 | 8dp 6 | 22dp 7 | 12dp 8 | 16dp 9 | 10 | -------------------------------------------------------------------------------- /files/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | This folder\'s empty! 4 | New Folder… 5 | New folder name 6 | 7 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 10 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 11 | org.gradle.jvmargs=-Xmx1536m 12 | # When configured, Gradle will run in incubating parallel mode. 13 | # This option should only be used with decoupled projects. More details, visit 14 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 15 | # org.gradle.parallel=true 16 | android.useAndroidX=true 17 | -------------------------------------------------------------------------------- /gradle/android_application_config.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | apply from: rootProject.file("gradle/android_common_config.gradle") 3 | 4 | if (module_package_id == null) { 5 | throw new IllegalStateException("module_package_id is missing!") 6 | } 7 | 8 | android.defaultConfig.applicationId = module_package_id.replace('-', '') -------------------------------------------------------------------------------- /gradle/android_common_config.gradle: -------------------------------------------------------------------------------- 1 | ext.module_package_id = "${module_group}.${module_name}" 2 | logger.info("Package ID: $module_package_id") 3 | 4 | apply plugin: "kotlin-android" 5 | apply from: rootProject.file("dependencies.gradle") 6 | apply from: rootProject.file("gradle/spotless_plugin_config.gradle") 7 | 8 | android { 9 | compileSdkVersion versions.compile_sdk 10 | buildToolsVersion versions.build_tools 11 | 12 | compileOptions { 13 | sourceCompatibility 1.8 14 | targetCompatibility 1.8 15 | } 16 | 17 | defaultConfig { 18 | minSdkVersion versions.min_sdk 19 | targetSdkVersion versions.compile_sdk 20 | versionCode versions.publish_version_code 21 | versionName versions.publish_version 22 | } 23 | 24 | sourceSets { 25 | main.res.srcDirs = [ 26 | "src/main/res", 27 | "src/main/res-public" 28 | ] 29 | } 30 | 31 | packagingOptions { 32 | exclude 'META-INF/atomicfu.kotlin_module' 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /gradle/android_library_config.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.library" 2 | 3 | apply from: rootProject.file("gradle/android_common_config.gradle") 4 | apply from: rootProject.file("gradle/android_publish_mavencentral.gradle") 5 | -------------------------------------------------------------------------------- /gradle/spotless_plugin_config.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.diffplug.gradle.spotless" 2 | spotless { 3 | java { 4 | target "**/*.java" 5 | trimTrailingWhitespace() 6 | removeUnusedImports() 7 | googleJavaFormat() 8 | endWithNewline() 9 | } 10 | kotlin { 11 | target "**/*.kt" 12 | ktlint().userData(["indent_size": "2", "continuation_indent_size": "2"]) 13 | licenseHeaderFile rootProject.file("spotless.license.kt") 14 | trimTrailingWhitespace() 15 | endWithNewline() 16 | } 17 | } -------------------------------------------------------------------------------- /gradle/versions_plugin_config.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.github.ben-manes.versions" 2 | 3 | dependencyUpdates.resolutionStrategy { 4 | componentSelection { rules -> 5 | rules.all { ComponentSelection selection -> 6 | boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm'].any { qualifier -> 7 | selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/ 8 | } 9 | if (rejected) { 10 | selection.reject('Not stable') 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip 6 | -------------------------------------------------------------------------------- /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 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 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 Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /input/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /input/build.gradle: -------------------------------------------------------------------------------- 1 | ext.module_group = "com.afollestad.material-dialogs" 2 | ext.module_name = "input" 3 | 4 | apply from: rootProject.file("gradle/android_library_config.gradle") 5 | 6 | dependencies { 7 | api project(':core') 8 | 9 | implementation deps.google_material 10 | implementation deps.kotlin.stdlib8 11 | } 12 | -------------------------------------------------------------------------------- /input/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /input/src/main/java/com/afollestad/materialdialogs/input/InputUtilExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogs.input 17 | 18 | import android.content.Context 19 | import android.view.View 20 | import android.view.inputmethod.InputMethodManager 21 | import com.afollestad.materialdialogs.MaterialDialog 22 | import com.afollestad.materialdialogs.WhichButton.POSITIVE 23 | import com.afollestad.materialdialogs.actions.setActionButtonEnabled 24 | 25 | internal fun MaterialDialog.invalidateInputMaxLength(allowEmpty: Boolean) { 26 | val currentLength = getInputField().text?.length ?: 0 27 | if (!allowEmpty && currentLength == 0) { 28 | return 29 | } 30 | val maxLength = getInputLayout().counterMaxLength 31 | if (maxLength > 0) { 32 | setActionButtonEnabled(POSITIVE, currentLength <= maxLength) 33 | } 34 | } 35 | 36 | internal fun MaterialDialog.showKeyboardIfApplicable() { 37 | getInputField().postRun { 38 | requestFocus() 39 | val imm = 40 | windowContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 41 | imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT) 42 | } 43 | } 44 | 45 | internal inline fun T.postRun(crossinline exec: T.() -> Unit) = this.post { 46 | this.exec() 47 | } 48 | -------------------------------------------------------------------------------- /input/src/main/res-public/values/public.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /input/src/main/res/layout/md_dialog_stub_input.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /input/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16sp 4 | 5 | -------------------------------------------------------------------------------- /lifecycle/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /lifecycle/build.gradle: -------------------------------------------------------------------------------- 1 | ext.module_group = "com.afollestad.material-dialogs" 2 | ext.module_name = "lifecycle" 3 | 4 | apply from: rootProject.file("gradle/android_library_config.gradle") 5 | 6 | dependencies { 7 | api project(':core') 8 | 9 | implementation deps.kotlin.stdlib8 10 | implementation deps.androidx.lifecycle.runtime 11 | annotationProcessor deps.androidx.lifecycle.compiler 12 | } 13 | -------------------------------------------------------------------------------- /lifecycle/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lifecycle/src/main/java/com/afollestad/materialdialogs/lifecycle/DialogLifecycleObserver.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | @file:Suppress("unused") 17 | 18 | package com.afollestad.materialdialogs.lifecycle 19 | 20 | import androidx.lifecycle.Lifecycle 21 | import androidx.lifecycle.LifecycleObserver 22 | import androidx.lifecycle.OnLifecycleEvent 23 | 24 | /** @author @jordyamc */ 25 | internal class DialogLifecycleObserver(private val dismiss: () -> Unit) : LifecycleObserver { 26 | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 27 | fun onDestroy() = dismiss() 28 | @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) 29 | fun onPause() = dismiss() 30 | } 31 | -------------------------------------------------------------------------------- /lifecycle/src/main/java/com/afollestad/materialdialogs/lifecycle/LifecycleExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | @file:Suppress("unused") 17 | 18 | package com.afollestad.materialdialogs.lifecycle 19 | 20 | import androidx.lifecycle.LifecycleOwner 21 | import com.afollestad.materialdialogs.MaterialDialog 22 | 23 | /** 24 | * Attach the dialog to a lifecycle and dismiss it when the lifecycle is destroyed. 25 | * Uses the given [owner] lifecycle if provided, else falls back to the Context of the dialog 26 | * window if it can. 27 | * 28 | * @param owner Optional lifecycle owner, if its null use windowContext. 29 | */ 30 | fun MaterialDialog.lifecycleOwner(owner: LifecycleOwner? = null): MaterialDialog { 31 | val observer = DialogLifecycleObserver(::dismiss) 32 | val lifecycleOwner = owner ?: (windowContext as? LifecycleOwner 33 | ?: throw IllegalStateException( 34 | "$windowContext is not a LifecycleOwner." 35 | )) 36 | lifecycleOwner.lifecycle.addObserver(observer) 37 | return this 38 | } 39 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | ext.module_group = "com.afollestad" 2 | ext.module_name = "materialdialogssample" 3 | 4 | apply from: rootProject.file("gradle/android_application_config.gradle") 5 | 6 | android.defaultConfig.vectorDrawables.useSupportLibrary = true 7 | 8 | dependencies { 9 | implementation project(':core') 10 | implementation project(':input') 11 | implementation project(':files') 12 | implementation project(':color') 13 | implementation project(':datetime') 14 | implementation project(':bottomsheets') 15 | implementation project(':lifecycle') 16 | 17 | implementation deps.kotlin.stdlib8 18 | 19 | implementation deps.androidx.core 20 | implementation deps.androidx.grid_layout 21 | implementation deps.androidx.recycler_view 22 | implementation deps.google_material 23 | 24 | implementation deps.afollestad.assent 25 | 26 | debugImplementation deps.leak_canary 27 | } 28 | -------------------------------------------------------------------------------- /sample/ic_web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/ic_web.png -------------------------------------------------------------------------------- /sample/sample.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/sample.apk -------------------------------------------------------------------------------- /sample/src/debug/java/com/afollestad/materialdialogssample/SampleApp.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogssample 17 | 18 | import android.app.Application 19 | import leakcanary.LeakCanary 20 | 21 | /** @author Aidan Follestad (afollestad) */ 22 | class SampleApp : Application() { 23 | 24 | override fun onCreate() { 25 | super.onCreate() 26 | LeakCanary.config = LeakCanary.config.copy(retainedVisibleThreshold = 3) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /sample/src/main/java/com/afollestad/materialdialogssample/Debouncer.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogssample 17 | 18 | import android.view.View 19 | 20 | internal object Debouncer { 21 | @Volatile private var enabled: Boolean = true 22 | private val enableAgain = Runnable { enabled = true } 23 | 24 | fun canPerform(view: View): Boolean { 25 | if (enabled) { 26 | enabled = false 27 | view.post(enableAgain) 28 | return true 29 | } 30 | return false 31 | } 32 | } 33 | 34 | internal fun T.onClickDebounced(click: (view: T) -> Unit) { 35 | setOnClickListener { 36 | if (Debouncer.canPerform(it)) { 37 | @Suppress("UNCHECKED_CAST") 38 | click(it as T) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sample/src/main/java/com/afollestad/materialdialogssample/Utils.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogssample 17 | 18 | import android.app.Activity 19 | import android.content.SharedPreferences 20 | import android.widget.Toast 21 | import java.text.SimpleDateFormat 22 | import java.util.Calendar 23 | import java.util.Locale 24 | 25 | private var toast: Toast? = null 26 | 27 | internal fun Activity.toast(message: CharSequence) { 28 | toast?.cancel() 29 | toast = Toast.makeText(this, message, Toast.LENGTH_SHORT) 30 | .apply { show() } 31 | } 32 | 33 | typealias PrefEditor = SharedPreferences.Editor 34 | 35 | internal fun SharedPreferences.boolean( 36 | key: String, 37 | defaultValue: Boolean = false 38 | ): Boolean { 39 | return getBoolean(key, defaultValue) 40 | } 41 | 42 | internal inline fun SharedPreferences.commit(crossinline exec: PrefEditor.() -> Unit) { 43 | val editor = this.edit() 44 | editor.exec() 45 | editor.apply() 46 | } 47 | 48 | internal fun Int.toHex() = "#${Integer.toHexString(this)}" 49 | 50 | internal fun Calendar.formatTime(): String { 51 | return SimpleDateFormat("kk:mm a", Locale.US).format(this.time) 52 | } 53 | 54 | internal fun Calendar.formatDate(): String { 55 | return SimpleDateFormat("MMMM dd, yyyy", Locale.US).format(this.time) 56 | } 57 | 58 | internal fun Calendar.formatDateTime(): String { 59 | return SimpleDateFormat("kk:mm a, MMMM dd, yyyy", Locale.US).format(this.time) 60 | } 61 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable/ic_icon_android.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /sample/src/main/res/font/raleway_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/font/raleway_bold.ttf -------------------------------------------------------------------------------- /sample/src/main/res/font/raleway_medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/font/raleway_medium.ttf -------------------------------------------------------------------------------- /sample/src/main/res/font/raleway_semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/font/raleway_semibold.ttf -------------------------------------------------------------------------------- /sample/src/main/res/layout/custom_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 26 | 27 | 35 | 36 | 44 | 45 | 53 | 54 | 62 | 63 | 71 | 72 | 83 | 84 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/custom_view_webview.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 15 | 16 | -------------------------------------------------------------------------------- /sample/src/main/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | 11 | 14 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afollestad/material-dialogs/709cfee9b45257af7ab4c428e4850bee38a075e7/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/values-v21/styles_parent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /sample/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Twitter 6 | Google+ 7 | Instagram 8 | Facebook 9 | 10 | 11 | 12 | Twitter is an online social networking service that enables users to send and read short 140-character messages called "tweets". 13 | Google+ is an interest-based social network that is owned and operated by Google Inc. The service is Google\'s fourth foray into social networking. 14 | Instagram is an online mobile photo-sharing, video-sharing and social networking service that enables its users to take pictures and videos, and share them on a variety of social networking platforms. 15 | Facebook is an online social networking service headquartered in Menlo Park, California. Its website was launched on February 4, 2004, by Mark Zuckerberg with friends. 16 | 17 | 18 | 19 | Alabama 20 | Alaska 21 | American Samoa 22 | Arizona 23 | Arkansas 24 | California 25 | Colorado 26 | Connecticut 27 | Delaware 28 | District of Columbia 29 | Florida 30 | Georgia 31 | Guam 32 | Hawaii 33 | Idaho 34 | Illinois 35 | Indiana 36 | Iowa 37 | Kansas 38 | Kentucky 39 | Louisiana 40 | Maine 41 | Maryland 42 | Massachusetts 43 | Michigan 44 | Minnesota 45 | Mississippi 46 | Missouri 47 | Montana 48 | Nebraska 49 | Nevada 50 | New Hampshire 51 | New Jersey 52 | New Mexico 53 | New York 54 | North Carolina 55 | North Dakota 56 | Northern Marianas Islands 57 | Ohio 58 | Oklahoma 59 | Oregon 60 | Pennsylvania 61 | Puerto Rico 62 | Rhode Island 63 | South Carolina 64 | South Dakota 65 | Tennessee 66 | Texas 67 | Utah 68 | Vermont 69 | Virginia 70 | Virgin Islands 71 | Washington 72 | West Virginia 73 | Wisconsin 74 | Wyoming 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /sample/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #6002ee 7 | #5002c7 8 | #9c47ff 9 | 10 | #607D8B 11 | #546E7A 12 | #388E3C 13 | #40388E3C 14 | 15 | 16 | -------------------------------------------------------------------------------- /sample/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 2dp 6 | 20sp 7 | 16dp 8 | 12dp 9 | 10 | 56dp 11 | 12 | 13 | 14sp 14 | 18sp 15 | 16 | 17 | -------------------------------------------------------------------------------- /sample/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #6002EE 4 | 5 | -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Material Dialogs 4 | 5 | Agree 6 | Disagree 7 | More Info 8 | 9 | Choose 10 | 11 | This app wants to access your location. 12 | Use Google\'s Location Services? 13 | Let Google help apps determine location. This means sending anonymous location data to Google, even when no apps are running. 14 | Material Dialogs is a library designed and developed by 16 | Aidan Follestad. As of 2018, Aidan currently works 17 | on the Square Device Experience team at Square.

18 | Thanks for using Material Dialogs! 19 | ]]>
20 | Social Networks 21 | States 22 | 23 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae metus nec sapien 24 | elementum interdum ac mollis tortor. Nunc porttitor metus placerat orci auctor, sed dictum 25 | magna dapibus. Morbi a lacus ante. Cum sociis natoque penatibus et magnis dis parturient montes, 26 | nascetur ridiculus mus. Proin posuere nisl imperdiet lectus elementum accumsan. Etiam lacinia 27 | nisi ut nulla fermentum tempus. Integer ornare lacinia diam non maximus. Vestibulum iaculis urna 28 | eu elementum scelerisque. Etiam nisl erat, bibendum vitae magna nec, convallis malesuada erat. 29 | Cras non porttitor nibh. Pellentesque rhoncus sem luctus felis tincidunt bibendum. Pellentesque 30 | vulputate eros at nulla sollicitudin volutpat. Pellentesque laoreet est sit amet erat laoreet, 31 | id molestie nulla efficitur. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed 32 | varius nisl at imperdiet facilisis. Nam in elit sit amet metus dignissim aliquam. Nulla et ante 33 | molestie, lobortis velit accumsan, ornare massa. Praesent scelerisque quam ipsum, et feugiat 34 | ante aliquet eget. Aenean ultricies vulputate sem. 35 | 36 | I understand what this means 37 | 38 | 39 | Signal strength 40 | Excellent 41 | Security 42 | 802.1x EAP 43 | Password 44 | SSID 45 | Material Dialogs 46 | Show password 47 | Google Wifi 48 | Connect 49 | 50 | 51 | Primary Colors 52 | Accent Colors 53 | Custom Colors 54 | Custom RGB 55 | Custom ARGB 56 | 57 | 58 | Select 59 | 60 |
61 | -------------------------------------------------------------------------------- /sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 17 | 18 | 34 | 35 | 47 | 48 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /sample/src/main/res/values/styles_parent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /sample/src/release/java/com/afollestad/materialdialogssample/SampleApp.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | package com.afollestad.materialdialogssample 17 | 18 | import android.app.Application 19 | 20 | /** 21 | * This does nothing in main variants. In debug, we configure leak canary. 22 | * 23 | * @author Aidan Follestad (afollestad) \ 24 | */ 25 | class SampleApp : Application() 26 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':core', ':sample', ':files', ':color', ':input', ':lifecycle', ':datetime', ':bottomsheets' 2 | -------------------------------------------------------------------------------- /spotless.license.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed and developed by Aidan Follestad (@afollestad) 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 | */ --------------------------------------------------------------------------------