├── .github ├── FUNDING.yml └── workflows │ └── build.yaml ├── .gitignore ├── LICENSE.md ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ │ └── com │ │ │ └── minar │ │ │ └── birday │ │ │ ├── activities │ │ │ ├── MainActivity.kt │ │ │ ├── MinimalWidgetConfigurationActivity.kt │ │ │ └── WelcomeActivity.kt │ │ │ ├── adapters │ │ │ ├── ContactsFilterArrayAdapter.kt │ │ │ ├── EventAdapter.kt │ │ │ ├── FavoritesAdapter.kt │ │ │ └── MissedCarouselAdapter.kt │ │ │ ├── animators │ │ │ └── BirdayRecyclerAnimator.kt │ │ │ ├── fragments │ │ │ ├── DetailsFragment.kt │ │ │ ├── ExperimentalSettingsFragment.kt │ │ │ ├── FavoritesFragment.kt │ │ │ ├── HomeFragment.kt │ │ │ ├── OverviewFragment.kt │ │ │ ├── SettingsFragment.kt │ │ │ └── dialogs │ │ │ │ ├── ImportContactsBottomSheet.kt │ │ │ │ ├── InsertEventBottomSheet.kt │ │ │ │ ├── QuickAppsBottomSheet.kt │ │ │ │ ├── RateBottomSheet.kt │ │ │ │ └── StatsBottomSheet.kt │ │ │ ├── model │ │ │ ├── ContactInfo.kt │ │ │ ├── Event.kt │ │ │ ├── EventCode.kt │ │ │ ├── EventDataItem.kt │ │ │ ├── EventResult.kt │ │ │ ├── EventType.kt │ │ │ └── ImportedEvent.kt │ │ │ ├── persistence │ │ │ ├── ContactsRepository.kt │ │ │ ├── EventDao.kt │ │ │ ├── EventDatabase.kt │ │ │ └── LocalDateTypeConverter.kt │ │ │ ├── preferences │ │ │ ├── backup │ │ │ │ ├── BirdayExporter.kt │ │ │ │ ├── BirdayImporter.kt │ │ │ │ ├── CalendarExporter.kt │ │ │ │ ├── CalendarImporter.kt │ │ │ │ ├── ContactsImporter.kt │ │ │ │ ├── CsvExporter.kt │ │ │ │ ├── CsvImporter.kt │ │ │ │ ├── JsonExporter.kt │ │ │ │ └── JsonImporter.kt │ │ │ └── standard │ │ │ │ ├── AddDemoEntriesPreference.kt │ │ │ │ ├── ClearDBPreference.kt │ │ │ │ ├── CustomAuthorPreference.kt │ │ │ │ ├── DisableOptimizationsPreference.kt │ │ │ │ ├── ExperimentalDisclaimerPreference.kt │ │ │ │ ├── NotificationSoundPreference.kt │ │ │ │ └── TimePickerPreference.kt │ │ │ ├── receivers │ │ │ └── NotificationActionReceiver.kt │ │ │ ├── utilities │ │ │ ├── AppRater.kt │ │ │ ├── CalendarUtils.kt │ │ │ ├── ChineseCalendarUtils.kt │ │ │ ├── ColorUtils.kt │ │ │ ├── DisplayUtils.kt │ │ │ ├── EventUtils.kt │ │ │ ├── FileUtils.kt │ │ │ ├── FragmentUtils.kt │ │ │ ├── ImageUtils.kt │ │ │ ├── LocalDateJsonSerializer.kt │ │ │ ├── StatsGenerator.kt │ │ │ └── TextUtils.kt │ │ │ ├── viewmodels │ │ │ ├── InsertEventViewModel.kt │ │ │ └── MainViewModel.kt │ │ │ ├── widgets │ │ │ ├── BirdayWidgetProvider.kt │ │ │ ├── EventWidgetProvider.kt │ │ │ ├── EventWidgetService.kt │ │ │ └── MinimalWidgetProvider.kt │ │ │ └── workers │ │ │ └── EventWorker.kt │ └── res │ │ ├── anim │ │ ├── nav_enter_anim.xml │ │ ├── nav_enter_secondary_anim.xml │ │ ├── nav_exit_anim.xml │ │ ├── nav_exit_secondary_anim.xml │ │ ├── nav_pop_enter_anim.xml │ │ ├── nav_pop_enter_secondary_anim.xml │ │ ├── nav_pop_exit_anim.xml │ │ └── nav_pop_exit_secondary_anim.xml │ │ ├── drawable-nodpi │ │ ├── birday_minimal_widget_preview.png │ │ ├── birday_widget_preview.png │ │ ├── icon_birday_angry_1.png │ │ ├── icon_birday_angry_10.png │ │ ├── icon_birday_angry_2.png │ │ ├── icon_birday_angry_3.png │ │ ├── icon_birday_angry_4.png │ │ ├── icon_birday_angry_5.png │ │ ├── icon_birday_angry_6.png │ │ ├── icon_birday_angry_7.png │ │ ├── icon_birday_angry_8.png │ │ ├── icon_birday_angry_9.png │ │ ├── icon_birday_eye_1.png │ │ ├── icon_birday_eye_2.png │ │ ├── icon_birday_eye_3.png │ │ ├── icon_birday_eye_4.png │ │ ├── icon_birday_eye_5.png │ │ ├── icon_birday_eye_6.png │ │ ├── icon_birday_normal.png │ │ ├── icon_birday_wing_1.png │ │ ├── icon_birday_wing_2.png │ │ ├── icon_birday_wing_3.png │ │ ├── icon_birday_wing_4.png │ │ ├── icon_birday_wing_5.png │ │ ├── icon_birday_wing_6.png │ │ ├── icon_birday_wing_7.png │ │ ├── icon_birday_wing_8.png │ │ ├── slide_one.png │ │ ├── slide_three.png │ │ └── slide_two.png │ │ ├── drawable │ │ ├── animated_add_event.xml │ │ ├── animated_angry_notification_icon.xml │ │ ├── animated_anniversary.xml │ │ ├── animated_arrow_left.xml │ │ ├── animated_arrow_right.xml │ │ ├── animated_balloon.xml │ │ ├── animated_birday.xml │ │ ├── animated_candle.xml │ │ ├── animated_candle_new.xml │ │ ├── animated_counter_background.xml │ │ ├── animated_death_anniversary.xml │ │ ├── animated_delete.xml │ │ ├── animated_edit_event.xml │ │ ├── animated_experimental_danger.xml │ │ ├── animated_from_favorite.xml │ │ ├── animated_insert_event.xml │ │ ├── animated_logo.xml │ │ ├── animated_name_day.xml │ │ ├── animated_nav_favorites.xml │ │ ├── animated_nav_home.xml │ │ ├── animated_nav_settings.xml │ │ ├── animated_no_results.xml │ │ ├── animated_notification_icon.xml │ │ ├── animated_other.xml │ │ ├── animated_overview.xml │ │ ├── animated_party_popper.xml │ │ ├── animated_quick_apps.xml │ │ ├── animated_review_star.xml │ │ ├── animated_ripple_circle.xml │ │ ├── animated_stats.xml │ │ ├── animated_to_favorite.xml │ │ ├── birday_branding_image.xml │ │ ├── birday_logo.xml │ │ ├── birday_logo_mono.xml │ │ ├── bottom_navbar_item.xml │ │ ├── colored_shadow_gradient.xml │ │ ├── custom_cursor.xml │ │ ├── dialog_bg_monet.xml │ │ ├── ic_alert_24dp.xml │ │ ├── ic_anniversary_24dp.xml │ │ ├── ic_app_behavior_24dp.xml │ │ ├── ic_apps_24dp.xml │ │ ├── ic_apps_dialer_24dp.xml │ │ ├── ic_apps_email_24dp.xml │ │ ├── ic_apps_messages_24dp.xml │ │ ├── ic_apps_messenger_24dp.xml │ │ ├── ic_apps_signal_24dp.xml │ │ ├── ic_apps_telegram_24dp.xml │ │ ├── ic_apps_threema_24dp.xml │ │ ├── ic_apps_viber_24dp.xml │ │ ├── ic_apps_whatsapp_24dp.xml │ │ ├── ic_arrow_left_24dp.xml │ │ ├── ic_arrow_right_24dp.xml │ │ ├── ic_arrow_up_24dp.xml │ │ ├── ic_backup_restore_24dp.xml │ │ ├── ic_balloon_24dp.xml │ │ ├── ic_clear_24dp.xml │ │ ├── ic_cool_black_24dp.xml │ │ ├── ic_customization_24dp.xml │ │ ├── ic_date_black_24dp.xml │ │ ├── ic_date_question_black_24dp.xml │ │ ├── ic_death_anniversary_24dp.xml │ │ ├── ic_delete_24dp.xml │ │ ├── ic_dot_black_24dp.xml │ │ ├── ic_dot_small_24dp.xml │ │ ├── ic_edit_24dp.xml │ │ ├── ic_event_type_black_24dp.xml │ │ ├── ic_favorites_24dp.xml │ │ ├── ic_github_black_24dp.xml │ │ ├── ic_home_24dp.xml │ │ ├── ic_instagram_black_24dp.xml │ │ ├── ic_inverted_circle_foreground_black_24dp.xml │ │ ├── ic_minar_logo_24dp.xml │ │ ├── ic_name_day_24dp.xml │ │ ├── ic_neutral_72dp.xml │ │ ├── ic_note_24dp.xml │ │ ├── ic_note_missing_24dp.xml │ │ ├── ic_notifications_24dp.xml │ │ ├── ic_octagram_24dp.xml │ │ ├── ic_other_24dp.xml │ │ ├── ic_party_24dp.xml │ │ ├── ic_party_white_24dp.xml │ │ ├── ic_pen_24dp.xml │ │ ├── ic_person_search_24dp.xml │ │ ├── ic_play_store_black_24dp.xml │ │ ├── ic_ring_24dp.xml │ │ ├── ic_sad_72dp.xml │ │ ├── ic_settings_24dp.xml │ │ ├── ic_share_black_24dp.xml │ │ ├── ic_smile_24dp.xml │ │ ├── ic_star_24dp.xml │ │ ├── ic_stats_24dp.xml │ │ ├── ic_translate_24dp.xml │ │ ├── ic_triangle_24dp.xml │ │ ├── ic_troubleshoot_24dp.xml │ │ ├── ic_zodiac_aquarius.xml │ │ ├── ic_zodiac_aries.xml │ │ ├── ic_zodiac_cancer.xml │ │ ├── ic_zodiac_capricorn.xml │ │ ├── ic_zodiac_gemini.xml │ │ ├── ic_zodiac_leo.xml │ │ ├── ic_zodiac_libra.xml │ │ ├── ic_zodiac_pisces.xml │ │ ├── ic_zodiac_sagittarius.xml │ │ ├── ic_zodiac_scorpio.xml │ │ ├── ic_zodiac_taurus.xml │ │ ├── ic_zodiac_virgo.xml │ │ ├── line.xml │ │ ├── nav_animation_favorites.xml │ │ ├── nav_animation_home.xml │ │ ├── nav_animation_settings.xml │ │ ├── placeholder_anniversary_image.xml │ │ ├── placeholder_birthday_image.xml │ │ ├── placeholder_death_image.xml │ │ ├── placeholder_name_day_image.xml │ │ ├── placeholder_other_image.xml │ │ ├── scroll_line_drawable.xml │ │ ├── scroll_thumb_drawable.xml │ │ ├── snackbar_background.xml │ │ ├── static_birday_dark.xml │ │ ├── static_birday_light.xml │ │ ├── static_branding_image.xml │ │ ├── static_notification_icon.xml │ │ ├── thumb.xml │ │ ├── time_picker_chip_background_color.xml │ │ ├── time_picker_chip_color.xml │ │ └── widget_inner_rounded_container.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_minimal_widget_configuration.xml │ │ ├── add_demo_entries_row.xml │ │ ├── author_preference_row.xml │ │ ├── birday_export_row.xml │ │ ├── birday_import_row.xml │ │ ├── bottom_sheet_import_contacts.xml │ │ ├── bottom_sheet_insert_event.xml │ │ ├── bottom_sheet_quick_apps.xml │ │ ├── bottom_sheet_rate.xml │ │ ├── bottom_sheet_stats.xml │ │ ├── calendar_export_row.xml │ │ ├── calendar_import_row.xml │ │ ├── clear_db_row.xml │ │ ├── contacts_import_row.xml │ │ ├── csv_export_row.xml │ │ ├── csv_import_row.xml │ │ ├── dialog_notes.xml │ │ ├── disable_optimizations_row.xml │ │ ├── event_row.xml │ │ ├── event_type_list_item.xml │ │ ├── experimental_disclaimer_row.xml │ │ ├── favorite_row.xml │ │ ├── fragment_details.xml │ │ ├── fragment_favorites.xml │ │ ├── fragment_home.xml │ │ ├── fragment_overview.xml │ │ ├── json_export_row.xml │ │ ├── json_import_row.xml │ │ ├── missed_carousel_item.xml │ │ ├── month_header_row.xml │ │ ├── notification_sound_row.xml │ │ ├── preference_switch_widget.xml │ │ ├── time_picker_row.xml │ │ ├── widget_minimal.xml │ │ ├── widget_row.xml │ │ └── widget_upcoming.xml │ │ ├── menu │ │ └── navigation_bottomappbar.xml │ │ ├── mipmap-anydpi │ │ ├── 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 │ │ ├── navigation │ │ └── nav_graph.xml │ │ ├── raw │ │ ├── birday_demo_entries.csv │ │ └── birday_notification.mp3 │ │ ├── resources.properties │ │ ├── values-b+sr+Latn │ │ └── strings.xml │ │ ├── values-ca │ │ └── strings.xml │ │ ├── values-cs │ │ └── strings.xml │ │ ├── values-de │ │ └── strings.xml │ │ ├── values-el │ │ └── strings.xml │ │ ├── values-es │ │ └── strings.xml │ │ ├── values-eu │ │ └── strings.xml │ │ ├── values-fi-rFI │ │ └── strings.xml │ │ ├── values-fr │ │ └── strings.xml │ │ ├── values-hi │ │ └── strings.xml │ │ ├── values-hr │ │ └── strings.xml │ │ ├── values-hu │ │ └── strings.xml │ │ ├── values-it │ │ └── strings.xml │ │ ├── values-ja │ │ └── strings.xml │ │ ├── values-ml │ │ └── strings.xml │ │ ├── values-mr │ │ └── strings.xml │ │ ├── values-nb-rNO │ │ └── strings.xml │ │ ├── values-night-v31 │ │ └── styles.xml │ │ ├── values-night │ │ └── styles.xml │ │ ├── values-nl │ │ └── strings.xml │ │ ├── values-nn-rNO │ │ └── strings.xml │ │ ├── values-no-rNO │ │ └── strings.xml │ │ ├── values-pl │ │ └── strings.xml │ │ ├── values-pt-rBR │ │ └── strings.xml │ │ ├── values-pt │ │ └── strings.xml │ │ ├── values-ro │ │ └── strings.xml │ │ ├── values-ru │ │ └── strings.xml │ │ ├── values-sk-rSK │ │ └── strings.xml │ │ ├── values-sr │ │ └── strings.xml │ │ ├── values-sv-rSE │ │ └── strings.xml │ │ ├── values-ta-rIN │ │ └── strings.xml │ │ ├── values-tr-rTR │ │ └── strings.xml │ │ ├── values-uk-rUA │ │ └── strings.xml │ │ ├── values-v27 │ │ └── styles.xml │ │ ├── values-v31 │ │ ├── arrays.xml │ │ └── styles.xml │ │ ├── values-v32 │ │ └── arrays.xml │ │ ├── values-vi │ │ └── strings.xml │ │ ├── values-zh-rCN │ │ └── strings.xml │ │ ├── values-zh-rTW │ │ └── strings.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── ids.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ ├── data_extraction_rules.xml │ │ ├── experimental_preferences.xml │ │ ├── filepaths.xml │ │ ├── fragment_details_scene.xml │ │ ├── fragment_favorites_scene.xml │ │ ├── fragment_home_scene.xml │ │ ├── preferences.xml │ │ ├── widget_minimal_info.xml │ │ └── widget_upcoming_info.xml │ └── test │ └── java │ └── com │ └── minar │ └── birday │ └── utils │ └── ChineseCalendarUnitTest.kt ├── build.gradle.kts ├── crowdin.yml ├── fastlane └── metadata │ └── android │ ├── en-US │ ├── changelogs │ │ ├── 10.txt │ │ ├── 11.txt │ │ ├── 13.txt │ │ ├── 14.txt │ │ ├── 15.txt │ │ ├── 19.txt │ │ ├── 20.txt │ │ ├── 21.txt │ │ ├── 23.txt │ │ ├── 25.txt │ │ ├── 26.txt │ │ ├── 27.txt │ │ ├── 31.txt │ │ ├── 33.txt │ │ ├── 8.txt │ │ └── 9.txt │ ├── full_description.txt │ ├── images │ │ ├── featureGraphic.png │ │ ├── icon.png │ │ └── phoneScreenshots │ │ │ ├── 01.png │ │ │ ├── 02.png │ │ │ ├── 03.png │ │ │ ├── 04.png │ │ │ ├── 05.png │ │ │ ├── 06.png │ │ │ ├── 07.png │ │ │ ├── 08.png │ │ │ ├── 09.png │ │ │ └── 10.png │ ├── short_description.txt │ └── title.txt │ └── fr-FR │ ├── full_description.txt │ ├── short_description.txt │ └── title.txt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── scripts └── check_translate_missing_strings.sh └── settings.gradle.kts /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: paypal.me/minardev 14 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [pull_request, push] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Setup Java 17 8 | uses: actions/setup-java@v3 9 | with: 10 | distribution: 'corretto' 11 | java-version: '17' 12 | - name: Checkout the code 13 | uses: actions/checkout@v2 14 | - name: Setup Android SDK 15 | uses: android-actions/setup-android@v3.2.0 16 | - name: Change wrapper permissions 17 | run: chmod +x ./gradlew 18 | - name: Build gradle project 19 | run: ./gradlew build 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | 12 | ### Android ### 13 | # Built application files 14 | *.apk 15 | *.aab 16 | *.ap_ 17 | output-metadata.json 18 | 19 | # Files for the ART/Dalvik VM 20 | *.dex 21 | 22 | # Java class files 23 | *.class 24 | 25 | # Generated files 26 | bin/ 27 | gen/ 28 | out/ 29 | 30 | # Gradle files 31 | .gradle/ 32 | build/ 33 | 34 | # Local configuration file (sdk path, etc) 35 | local.properties 36 | 37 | # Proguard folder generated by Eclipse 38 | proguard/ 39 | 40 | # Log Files 41 | *.log 42 | 43 | # Android Studio Navigation editor temp files 44 | .navigation/ 45 | 46 | # Android Studio captures folder 47 | captures/ 48 | 49 | # Intellij 50 | *.iml 51 | .idea/ 52 | 53 | # External native build folder generated in Android Studio 2.2 and later 54 | .externalNativeBuild 55 | 56 | # Freeline 57 | freeline.py 58 | freeline/ 59 | freeline_project_description.json 60 | 61 | # Android Patch 62 | gen-external-apklibs 63 | 64 | # Json Output 65 | app/debug/output.json 66 | app/release/output.json -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | release 3 | debug -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | -keep class com.minar.birday.model.EventResult 9 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/fragments/dialogs/ImportContactsBottomSheet.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.fragments.dialogs 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import androidx.fragment.app.activityViewModels 9 | import androidx.lifecycle.lifecycleScope 10 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment 11 | import com.minar.birday.R 12 | import com.minar.birday.activities.MainActivity 13 | import com.minar.birday.databinding.BottomSheetImportContactsBinding 14 | import com.minar.birday.persistence.ContactsRepository 15 | import com.minar.birday.viewmodels.MainViewModel 16 | import kotlinx.coroutines.Dispatchers 17 | import kotlinx.coroutines.launch 18 | import kotlinx.coroutines.withContext 19 | 20 | class ImportContactsBottomSheet : BottomSheetDialogFragment() { 21 | private val viewModel: MainViewModel by activityViewModels() 22 | private lateinit var act: MainActivity 23 | private val contactsRepository = ContactsRepository() 24 | 25 | override fun onCreateView( 26 | inflater: LayoutInflater, 27 | container: ViewGroup?, 28 | savedInstanceState: Bundle? 29 | ): View { 30 | act = requireActivity() as MainActivity 31 | return BottomSheetImportContactsBinding.inflate(inflater, container, false).root 32 | } 33 | 34 | @SuppressLint("MissingPermission") 35 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 36 | val binding = BottomSheetImportContactsBinding.bind(view) 37 | 38 | act.animateAvd( 39 | binding.importContactsImage, 40 | R.drawable.animated_balloon, 1500L 41 | ) 42 | 43 | binding.importContactsCancelButton.setOnClickListener { dismiss() } 44 | 45 | binding.importContactsConfirmButton.setOnClickListener { 46 | binding.importContactsButtons.visibility = View.INVISIBLE 47 | binding.importContactsProgressIndicator.visibility = View.VISIBLE 48 | 49 | // Actually import contacts 50 | viewLifecycleOwner.lifecycleScope.launch { 51 | val events = withContext(Dispatchers.IO) { 52 | contactsRepository.getEventsFromContacts(requireContext().contentResolver) 53 | } 54 | 55 | viewModel.insertAll(events) 56 | 57 | dismiss() 58 | } 59 | } 60 | } 61 | 62 | companion object { 63 | const val TAG = "import_contacts_bottom_sheet" 64 | } 65 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/model/ContactInfo.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.model 2 | 3 | /** 4 | * Data class to group together the smallest information about a contact, 5 | * when extracted from the contacts list. 6 | * 7 | * Not intended to be an entity, but just a POJO in our business logic. 8 | */ 9 | data class ContactInfo( 10 | val id: String, 11 | val name: String, 12 | val surname: String, 13 | val image: ByteArray?, 14 | ) { 15 | val fullName: String 16 | get() = 17 | if (surname.isBlank()) 18 | name 19 | else 20 | "$name,$surname".replace("\\s".toRegex(), " ") 21 | 22 | override fun toString() = "$name $surname" 23 | 24 | override fun equals(other: Any?): Boolean { 25 | if (this === other) return true 26 | if (javaClass != other?.javaClass) return false 27 | 28 | other as ContactInfo 29 | 30 | if (id != other.id) return false 31 | if (name != other.name) return false 32 | if (surname != other.surname) return false 33 | if (image != null) { 34 | if (other.image == null) return false 35 | if (!image.contentEquals(other.image)) return false 36 | } else if (other.image != null) return false 37 | 38 | return true 39 | } 40 | 41 | override fun hashCode(): Int { 42 | var result = id.hashCode() 43 | result = 31 * result + name.hashCode() 44 | result = 31 * result + surname.hashCode() 45 | result = 31 * result + (image?.contentHashCode() ?: 0) 46 | return result 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/model/Event.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.model 2 | 3 | import androidx.room.ColumnInfo 4 | import androidx.room.Entity 5 | import androidx.room.Index 6 | import androidx.room.PrimaryKey 7 | import com.google.gson.annotations.Expose 8 | import java.time.LocalDate 9 | 10 | @Entity( 11 | indices = [Index( 12 | value = arrayOf("name", "surname", "originalDate"), 13 | unique = true 14 | )] 15 | ) 16 | data class Event( 17 | @PrimaryKey(autoGenerate = true) 18 | val id: Int, 19 | @Expose 20 | val type: String? = EventCode.BIRTHDAY.name, 21 | @Expose 22 | val name: String, 23 | @Expose 24 | val surname: String? = "", 25 | val favorite: Boolean? = false, 26 | @Expose 27 | val yearMatter: Boolean? = true, 28 | @Expose 29 | val originalDate: LocalDate, 30 | @Expose 31 | val notes: String? = "", 32 | @ColumnInfo(typeAffinity = ColumnInfo.BLOB) 33 | val image: ByteArray? = null, 34 | ) { 35 | override fun equals(other: Any?): Boolean { 36 | if (this === other) return true 37 | if (javaClass != other?.javaClass) return false 38 | 39 | other as Event 40 | 41 | if (id != other.id) return false 42 | if (type != other.type) return false 43 | if (name != other.name) return false 44 | if (surname != other.surname) return false 45 | if (originalDate != other.originalDate) return false 46 | if (!image.contentEquals(other.image)) return false 47 | 48 | return true 49 | } 50 | 51 | override fun hashCode(): Int { 52 | var result = id 53 | result = 31 * result + (type?.hashCode() ?: 0) 54 | result = 31 * result + name.hashCode() 55 | result = 31 * result + (surname?.hashCode() ?: 0) 56 | result = 31 * result + (favorite?.hashCode() ?: 0) 57 | result = 31 * result + (yearMatter?.hashCode() ?: 0) 58 | result = 31 * result + originalDate.hashCode() 59 | result = 31 * result + (notes?.hashCode() ?: 0) 60 | result = 31 * result + (image?.contentHashCode() ?: 0) 61 | return result 62 | } 63 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/model/EventCode.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.model 2 | 3 | enum class EventCode { 4 | BIRTHDAY, 5 | ANNIVERSARY, 6 | DEATH, 7 | NAME_DAY, 8 | OTHER 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/model/EventDataItem.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.model 2 | 3 | // A wrapper around EventResult, to also consider the month header as an object 4 | sealed class EventDataItem { 5 | data class EventItem(val eventResult: EventResult) : EventDataItem() { 6 | override val id = eventResult.id.toLong() 7 | } 8 | 9 | data class IndexHeader(val headerTitle: String) : EventDataItem() { 10 | override val id = Long.MIN_VALUE 11 | } 12 | 13 | abstract val id: Long 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/model/EventResult.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.model 2 | 3 | import java.io.Serializable 4 | import java.time.LocalDate 5 | 6 | data class EventResult ( 7 | val id: Int, 8 | val type: String? = EventCode.BIRTHDAY.name, 9 | var name: String, 10 | var surname: String? = "", 11 | var favorite: Boolean? = false, 12 | val yearMatter: Boolean? = true, 13 | var originalDate: LocalDate, 14 | val nextDate: LocalDate? = null, 15 | var notes: String? = "", 16 | val image: ByteArray? = null, 17 | ): Serializable { 18 | override fun equals(other: Any?): Boolean { 19 | if (this === other) return true 20 | if (javaClass != other?.javaClass) return false 21 | 22 | other as EventResult 23 | 24 | if (id != other.id) return false 25 | if (type != other.type) return false 26 | if (name != other.name) return false 27 | if (surname != other.surname) return false 28 | if (yearMatter != other.yearMatter) return false 29 | if (originalDate != other.originalDate) return false 30 | if (!image.contentEquals(other.image)) return false 31 | 32 | return true 33 | } 34 | 35 | override fun hashCode(): Int { 36 | var result = id 37 | result = 31 * result + (type?.hashCode() ?: 0) 38 | result = 31 * result + name.hashCode() 39 | result = 31 * result + (surname?.hashCode() ?: 0) 40 | result = 31 * result + (favorite?.hashCode() ?: 0) 41 | result = 31 * result + (yearMatter?.hashCode() ?: 0) 42 | result = 31 * result + originalDate.hashCode() 43 | result = 31 * result + (nextDate?.hashCode() ?: 0) 44 | result = 31 * result + (notes?.hashCode() ?: 0) 45 | result = 31 * result + (image?.contentHashCode() ?: 0) 46 | return result 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/model/EventType.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.model 2 | 3 | data class EventType(val codeName: EventCode, val value: String) { 4 | override fun toString(): String = value // The value shown in the spinner 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/model/ImportedEvent.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.model 2 | 3 | // Used to hold an imported contact in contacts importer 4 | data class ImportedEvent( 5 | val id: String, 6 | val completeName: String, 7 | val eventDate: String, 8 | val image: ByteArray? = null, 9 | val eventType: String = EventCode.BIRTHDAY.name, 10 | val customLabel: String? = null 11 | ) { 12 | override fun equals(other: Any?): Boolean { 13 | if (this === other) return true 14 | if (javaClass != other?.javaClass) return false 15 | 16 | other as ImportedEvent 17 | 18 | if (completeName != other.completeName) return false 19 | if (eventDate != other.eventDate) return false 20 | if (eventType != other.eventType) return false 21 | if (!image.contentEquals(other.image)) return false 22 | 23 | return true 24 | } 25 | 26 | override fun hashCode(): Int { 27 | var result = completeName.hashCode() 28 | result = 31 * result + eventDate.hashCode() 29 | result = 31 * result + image.contentHashCode() 30 | return result 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/persistence/EventDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.persistence 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import androidx.room.TypeConverters 8 | import androidx.room.migration.Migration 9 | import androidx.sqlite.db.SupportSQLiteDatabase 10 | import com.minar.birday.model.Event 11 | 12 | 13 | @Database(entities = [Event::class], version = 11, exportSchema = false) 14 | @TypeConverters(LocalDateTypeConverter::class) 15 | abstract class EventDatabase : RoomDatabase() { 16 | abstract fun eventDao(): EventDao 17 | 18 | companion object { 19 | @Volatile 20 | private var INSTANCE: EventDatabase? = null 21 | 22 | // Migration strategy to add two columns from version 9 to 10 23 | private val MIGRATION_9_10: Migration = object : Migration(9, 10) { 24 | override fun migrate(db: SupportSQLiteDatabase) { 25 | db.execSQL( 26 | "ALTER TABLE Event ADD COLUMN notes TEXT DEFAULT ''" 27 | ) 28 | db.execSQL( 29 | "ALTER TABLE Event ADD COLUMN image BLOB" 30 | ) 31 | } 32 | } 33 | // Migration strategy to uppercase the type from version 10 to 11 34 | private val MIGRATION_10_11: Migration = object : Migration(10, 11) { 35 | override fun migrate(db: SupportSQLiteDatabase) { 36 | db.execSQL( 37 | "UPDATE Event SET type = UPPER(type)" 38 | ) 39 | } 40 | } 41 | fun getBirdayDatabase(context: Context): EventDatabase { 42 | val tempInstance = INSTANCE 43 | if (tempInstance != null) { 44 | return tempInstance 45 | } 46 | synchronized(this) { 47 | val instance = Room.databaseBuilder( 48 | context.applicationContext, 49 | EventDatabase::class.java, 50 | "BirdayDB" 51 | ) 52 | .addMigrations(MIGRATION_9_10) 53 | .addMigrations(MIGRATION_10_11) 54 | .build() 55 | INSTANCE = instance 56 | return instance 57 | } 58 | } 59 | 60 | fun destroyInstance() { 61 | if (INSTANCE?.isOpen == true) { 62 | INSTANCE?.close() 63 | } 64 | INSTANCE = null 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/persistence/LocalDateTypeConverter.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.persistence 2 | 3 | import androidx.room.TypeConverter 4 | import java.lang.Exception 5 | import java.time.LocalDate 6 | 7 | class LocalDateTypeConverter { 8 | @TypeConverter 9 | fun stringToLocalDate(value: String?): LocalDate { 10 | // Extra steps to avoid crashes for leap years 11 | return try { 12 | if (value == null) LocalDate.now() 13 | else LocalDate.parse(value) 14 | } catch (e: Exception) { 15 | if (value!!.substring(5) == "02-29") 16 | LocalDate.parse("${value.substring(0,5)}03-01") 17 | else LocalDate.now() 18 | } 19 | } 20 | 21 | @TypeConverter 22 | fun localDateToString(date: LocalDate?): String? { 23 | return date?.toString() 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/preferences/backup/JsonImporter.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.preferences.backup 2 | 3 | import android.content.Context 4 | import android.net.Uri 5 | import android.util.AttributeSet 6 | import android.view.View 7 | import androidx.preference.Preference 8 | import androidx.preference.PreferenceViewHolder 9 | import com.google.gson.GsonBuilder 10 | import com.minar.birday.R 11 | import com.minar.birday.activities.MainActivity 12 | import com.minar.birday.model.Event 13 | import com.minar.birday.utilities.LocalDateJsonSerializer 14 | import com.minar.birday.utilities.normalizeEvent 15 | import java.time.LocalDate 16 | import java.util.* 17 | 18 | 19 | class JsonImporter(context: Context, attrs: AttributeSet?) : Preference(context, attrs), 20 | View.OnClickListener { 21 | private val act = context as MainActivity 22 | 23 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 24 | super.onBindViewHolder(holder) 25 | val v = holder.itemView 26 | v.setOnClickListener(this) 27 | } 28 | 29 | // Vibrate and import the backup if possible 30 | override fun onClick(v: View) { 31 | act.vibrate() 32 | act.selectBackup.launch("application/json") 33 | } 34 | 35 | // Import a backup with basic checks and add the entries to the current DB 36 | fun importEventsJson(context: Context, fileUri: Uri): Boolean { 37 | val fileStream = context.contentResolver.openInputStream(fileUri)!! 38 | val jsonString = fileStream.bufferedReader().use { it.readText() } 39 | val gsonBuilder = GsonBuilder().registerTypeAdapter( 40 | LocalDate::class.java, 41 | LocalDateJsonSerializer().nullSafe() 42 | ).create() 43 | try { 44 | val importedEvents = gsonBuilder.fromJson(jsonString, Array::class.java).toList() 45 | // Normalize the events and add them to another list 46 | val normalizedEvents = mutableListOf() 47 | importedEvents.forEach { normalizedEvents.add(normalizeEvent(it)) } 48 | 49 | // Bulk insert, using the standard duplicate detection strategy 50 | act.mainViewModel.insertAll(normalizedEvents) 51 | fileStream.close() 52 | (context as MainActivity).showSnackbar(context.getString(R.string.birday_import_success)) 53 | } catch (e: Exception) { 54 | (context as MainActivity).showSnackbar(context.getString(R.string.birday_import_failure)) 55 | e.printStackTrace() 56 | return false 57 | } 58 | // No restart needed, since the events are normally inserted in the DB 59 | return true 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/preferences/standard/ClearDBPreference.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.preferences.standard 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import androidx.preference.Preference 7 | import androidx.preference.PreferenceViewHolder 8 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 9 | import com.minar.birday.R 10 | import com.minar.birday.activities.MainActivity 11 | import com.minar.birday.databinding.ClearDbRowBinding 12 | import com.minar.birday.persistence.EventDatabase 13 | import com.minar.birday.utilities.smartFixName 14 | import kotlinx.coroutines.CoroutineScope 15 | import kotlinx.coroutines.Dispatchers 16 | import kotlinx.coroutines.launch 17 | 18 | 19 | // A custom preference to nuke the DB 20 | class ClearDBPreference(context: Context, attrs: AttributeSet?) : 21 | Preference(context, attrs), 22 | View.OnClickListener { 23 | private lateinit var binding: ClearDbRowBinding 24 | 25 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 26 | super.onBindViewHolder(holder) 27 | binding = ClearDbRowBinding.bind(holder.itemView) 28 | binding.root.setOnClickListener(this) 29 | } 30 | 31 | override fun onClick(v: View) { 32 | val act = context as MainActivity 33 | act.vibrate() 34 | 35 | MaterialAlertDialogBuilder(act) 36 | .setTitle(R.string.delete_db_dialog_title) 37 | .setIcon(R.drawable.ic_alert_24dp) 38 | .setMessage(R.string.delete_db_dialog_description) 39 | .setPositiveButton(act.resources.getString(android.R.string.ok)) { dialog, _ -> 40 | CoroutineScope(Dispatchers.IO).launch { 41 | // Delete every saved data and send a snackbar 42 | EventDatabase.getBirdayDatabase(context).clearAllTables() 43 | }.invokeOnCompletion { 44 | act.showSnackbar( 45 | context.getString(R.string.app_intro_done_button).lowercase() 46 | .smartFixName(forceCapitalize = true) 47 | ) 48 | dialog.dismiss() 49 | } 50 | } 51 | .setNegativeButton(act.resources.getString(android.R.string.cancel)) { dialog, _ -> 52 | dialog.dismiss() 53 | } 54 | .show() 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/preferences/standard/DisableOptimizationsPreference.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.preferences.standard 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.provider.Settings 6 | import android.util.AttributeSet 7 | import android.view.View 8 | import android.widget.Toast 9 | import androidx.preference.Preference 10 | import androidx.preference.PreferenceViewHolder 11 | import com.minar.birday.R 12 | import com.minar.birday.databinding.DisableOptimizationsRowBinding 13 | 14 | 15 | // A custom preference to open the battery optimization settings 16 | class DisableOptimizationsPreference(context: Context, attrs: AttributeSet?) : 17 | Preference(context, attrs), 18 | View.OnClickListener { 19 | private lateinit var binding: DisableOptimizationsRowBinding 20 | 21 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 22 | super.onBindViewHolder(holder) 23 | binding = DisableOptimizationsRowBinding.bind(holder.itemView) 24 | binding.root.setOnClickListener(this) 25 | // Include the tutorial in the description itself, since the toast can be unreadable with big text sizes 26 | binding.batteryOptimizationsDescription.text = buildString { 27 | append(context.getString(R.string.battery_optimization_description)) 28 | append("\n\n") 29 | append(context.getString(R.string.battery_optimization_tutorial)) 30 | } 31 | } 32 | 33 | override fun onClick(v: View) { 34 | try { 35 | val intent = Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS) 36 | context.startActivity(intent) 37 | // Double tasty toast for a longer reading time 38 | Toast.makeText( 39 | context, 40 | context.getString(R.string.battery_optimization_tutorial), 41 | Toast.LENGTH_LONG 42 | ).show() 43 | Toast.makeText( 44 | context, 45 | context.getString(R.string.battery_optimization_tutorial), 46 | Toast.LENGTH_LONG 47 | ).show() 48 | } catch (e: Exception) { 49 | Toast.makeText( 50 | context, context.getString(R.string.wtf), Toast.LENGTH_LONG 51 | ).show() 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/preferences/standard/ExperimentalDisclaimerPreference.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.preferences.standard 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.net.Uri 6 | import android.util.AttributeSet 7 | import androidx.preference.Preference 8 | import androidx.preference.PreferenceViewHolder 9 | import com.minar.birday.BuildConfig 10 | import com.minar.birday.R 11 | import com.minar.birday.activities.MainActivity 12 | import com.minar.birday.databinding.ExperimentalDisclaimerRowBinding 13 | 14 | 15 | class ExperimentalDisclaimerPreference(context: Context, attrs: AttributeSet?) : 16 | Preference(context, attrs) { 17 | 18 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 19 | super.onBindViewHolder(holder) 20 | val binding = ExperimentalDisclaimerRowBinding.bind(holder.itemView) 21 | 22 | // Animate the vector drawable 23 | (context as MainActivity).animateAvd( 24 | binding.animatedDanger, 25 | R.drawable.animated_experimental_danger, 1500 26 | ) 27 | 28 | // Set the "open Github develop branch" button 29 | binding.checkGithubButton.setOnClickListener { 30 | (context as MainActivity).vibrate() 31 | val uri = Uri.parse(context.getString(R.string.github_repo_develop)) 32 | context.startActivity(Intent(Intent.ACTION_VIEW, uri)) 33 | } 34 | 35 | // Set the "translate the app" button 36 | binding.translateButton.setOnClickListener { 37 | (context as MainActivity).vibrate() 38 | val uri = Uri.parse(context.getString(R.string.crowdin_project)) 39 | context.startActivity(Intent(Intent.ACTION_VIEW, uri)) 40 | } 41 | 42 | // Set the app version name and number text 43 | val versionCode = BuildConfig.VERSION_CODE 44 | val versionName = BuildConfig.VERSION_NAME 45 | val versionInfo = "v$versionName ($versionCode)" 46 | binding.appVersionInfo.text = versionInfo 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/preferences/standard/NotificationSoundPreference.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.preferences.standard 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.provider.Settings 6 | import android.util.AttributeSet 7 | import android.view.View 8 | import android.widget.Toast 9 | import androidx.preference.Preference 10 | import androidx.preference.PreferenceViewHolder 11 | import com.minar.birday.R 12 | import com.minar.birday.databinding.NotificationSoundRowBinding 13 | 14 | 15 | // A custom preference to open the notification sound settings for Birday 16 | class NotificationSoundPreference(context: Context, attrs: AttributeSet?) : 17 | Preference(context, attrs), 18 | View.OnClickListener { 19 | private lateinit var binding: NotificationSoundRowBinding 20 | 21 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 22 | super.onBindViewHolder(holder) 23 | binding = NotificationSoundRowBinding.bind(holder.itemView) 24 | binding.root.setOnClickListener(this) 25 | } 26 | 27 | override fun onClick(v: View) { 28 | try { 29 | val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) 30 | .putExtra("android.provider.extra.APP_PACKAGE", context.packageName) 31 | .putExtra(Settings.EXTRA_CHANNEL_ID, "events_channel") 32 | context.startActivity(intent) 33 | } catch (e: Exception) { 34 | Toast.makeText( 35 | context, context.getString(R.string.wtf), Toast.LENGTH_LONG 36 | ).show() 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/receivers/NotificationActionReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.receivers 2 | 3 | import android.app.NotificationManager 4 | import android.content.BroadcastReceiver 5 | import android.content.Context 6 | import android.content.Intent 7 | 8 | class NotificationActionReceiver : BroadcastReceiver() { 9 | @Override 10 | override fun onReceive(context: Context, intent: Intent) { 11 | if (Intent.ACTION_BOOT_COMPLETED != intent.action) { 12 | val notificationId: Int = intent.getIntExtra("notificationId", 0) 13 | 14 | // Just cancel the notification. Any additional logic goes above this block 15 | val manager: NotificationManager = 16 | context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 17 | manager.cancel(notificationId) 18 | } 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/utilities/AppRater.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.utilities 2 | 3 | import android.content.SharedPreferences 4 | import androidx.fragment.app.FragmentActivity 5 | import com.minar.birday.activities.MainActivity 6 | import com.minar.birday.fragments.dialogs.RateBottomSheet 7 | 8 | object AppRater { 9 | 10 | private const val DO_NOT_SHOW_AGAIN = "do_not_show_again" 11 | private const val APP_RATING = "app_rating" 12 | private const val LAUNCH_COUNT = "launch_count" 13 | private const val DATE_FIRST_LAUNCH = "date_first_launch" 14 | private const val DAYS_UNTIL_PROMPT = 2 // Min number of days 15 | private const val LAUNCHES_UNTIL_PROMPT = 3 // Min number of launches 16 | 17 | @JvmStatic 18 | fun appLaunched(activity: MainActivity) { 19 | val prefs = activity.getSharedPreferences(APP_RATING, 0) 20 | if (prefs.getBoolean(DO_NOT_SHOW_AGAIN, false)) return 21 | val editor = prefs.edit() 22 | 23 | // Increment launch counter 24 | val launchCount = prefs.getLong(LAUNCH_COUNT, 0) + 1 25 | editor.putLong(LAUNCH_COUNT, launchCount) 26 | 27 | // Get date of first launch 28 | var dateFirstLaunch = prefs.getLong(DATE_FIRST_LAUNCH, 0) 29 | if (dateFirstLaunch == 0L) { 30 | dateFirstLaunch = System.currentTimeMillis() 31 | editor.putLong(DATE_FIRST_LAUNCH, dateFirstLaunch) 32 | } 33 | 34 | // Wait at least n days before opening 35 | if (launchCount >= LAUNCHES_UNTIL_PROMPT) { 36 | if (System.currentTimeMillis() >= dateFirstLaunch + DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000) { 37 | showRateDialog(activity, editor) 38 | } 39 | } 40 | editor.apply() 41 | } 42 | 43 | private fun showRateDialog(activity: FragmentActivity, editor: SharedPreferences.Editor) { 44 | val bottomSheet = RateBottomSheet(editor) 45 | if (bottomSheet.isAdded) return 46 | bottomSheet.show(activity.supportFragmentManager, "rate_bottom_sheet") 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/utilities/ChineseCalendarUtils.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.utilities 2 | 3 | import android.icu.util.* 4 | import java.time.LocalDate 5 | import java.time.ZoneOffset 6 | 7 | // Adapter to use either Android's provided ICU or the original one. 8 | interface CalendarAdapter { 9 | 10 | // Wrapper for Calendar.setTimeInMillis 11 | fun setTimeInMillis(value: Long) 12 | 13 | // Wrapper for Calendar.get 14 | fun get(field: Int): Int 15 | } 16 | 17 | /** 18 | * Finds the Chinese calendar year animal corresponding to the given date, using the provided 19 | * ICU implementation. 20 | * @param getChinese Function to create a Chinese calendar 21 | * @returns Animal index, starting from 0 = rat 22 | */ 23 | fun chineseAnimalGeneric(getChinese: () -> C, date: LocalDate): Int { 24 | // Convert the given date to a UNIX epoch value, assuming Beijing time 25 | val millis = date.atTime(12, 0) 26 | .toInstant(ZoneOffset.ofHours(8)) 27 | .toEpochMilli() 28 | // Create a Chinese calendar instance for the given epoch value 29 | val chinese = getChinese() 30 | chinese.setTimeInMillis(millis) 31 | // Extract the year, which corresponds to the animal cycle 32 | val year = chinese.get(Calendar.YEAR) 33 | return (year - 1) % 12 34 | } 35 | 36 | // Implementation of calendar adapter for Android-provided ICU. 37 | class AndroidCalendar(private val calendar: Calendar): CalendarAdapter { 38 | override fun setTimeInMillis(value: Long) { 39 | calendar.timeInMillis = value 40 | } 41 | override fun get(field: Int): Int = calendar.get(field) 42 | } 43 | 44 | // Return the Animal index (starting from 0 = rat) corresponding to the given date 45 | fun chineseAnimal(date: LocalDate): Int = chineseAnimalGeneric( 46 | getChinese = { AndroidCalendar(ChineseCalendar()) }, 47 | date 48 | ) 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/utilities/ColorUtils.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.utilities 2 | 3 | import android.content.Context 4 | import android.util.TypedValue 5 | import androidx.annotation.AttrRes 6 | 7 | // Return any attr color, to use it programmatically 8 | fun getThemeColor(@AttrRes attrRes: Int, context: Context): Int { 9 | val typedValue = TypedValue() 10 | context.theme.resolveAttribute(attrRes, typedValue, true) 11 | return typedValue.data 12 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/utilities/FileUtils.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.utilities 2 | 3 | import android.content.ContentResolver 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.net.Uri 7 | import androidx.annotation.AnyRes 8 | import androidx.core.content.FileProvider 9 | import com.minar.birday.BuildConfig 10 | import java.io.File 11 | 12 | // Share the backup to a supported app 13 | fun shareFile(context: Context, fileUri: String) { 14 | val file = File(fileUri) 15 | val contentUri: Uri = 16 | FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file) 17 | val shareIntent = Intent().apply { 18 | action = Intent.ACTION_SEND 19 | putExtra(Intent.EXTRA_STREAM, contentUri) 20 | type = "*/*" 21 | } 22 | // Verify that the intent will resolve to an activity 23 | if (shareIntent.resolveActivity(context.packageManager) != null) 24 | context.startActivity(shareIntent) 25 | } 26 | 27 | // Get the URI for a file in the raw folder 28 | fun getResourceUri(@AnyRes resourceId: Int): Uri = 29 | Uri.Builder() 30 | .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) 31 | .authority(BuildConfig.APPLICATION_ID) 32 | .path(resourceId.toString()) 33 | .build() -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/utilities/FragmentUtils.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.utilities 2 | 3 | import androidx.fragment.app.DialogFragment 4 | import androidx.fragment.app.FragmentManager 5 | 6 | fun DialogFragment.showIfNotAdded(fragmentManager: FragmentManager, tag: String) { 7 | if (!isAdded) { 8 | show(fragmentManager, tag) 9 | } 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/utilities/LocalDateJsonSerializer.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.utilities 2 | 3 | import com.google.gson.TypeAdapter 4 | import com.google.gson.stream.JsonReader 5 | import com.google.gson.stream.JsonWriter 6 | import java.time.LocalDate 7 | import java.time.format.DateTimeFormatter 8 | 9 | // This class helps gson to serialize and deserialize a LocalDate 10 | class LocalDateJsonSerializer : TypeAdapter() { 11 | 12 | // Write a date to JSON, using a standard format 13 | override fun write(out: JsonWriter, value: LocalDate) { 14 | out.value(DateTimeFormatter.ISO_LOCAL_DATE.format(value)) 15 | } 16 | 17 | // Read a date from JSON. If invalid, return the actual date 18 | override fun read(input: JsonReader): LocalDate { 19 | return try { 20 | LocalDate.parse(input.nextString()) 21 | } catch (e: Exception) { 22 | LocalDate.now() 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/viewmodels/InsertEventViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.viewmodels 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Application 5 | import androidx.lifecycle.AndroidViewModel 6 | import androidx.lifecycle.LiveData 7 | import androidx.lifecycle.MutableLiveData 8 | import androidx.lifecycle.viewModelScope 9 | import com.minar.birday.activities.MainActivity 10 | import com.minar.birday.model.ContactInfo 11 | import com.minar.birday.persistence.ContactsRepository 12 | import kotlinx.coroutines.Dispatchers 13 | import kotlinx.coroutines.launch 14 | import kotlinx.coroutines.withContext 15 | 16 | @ExperimentalStdlibApi 17 | class InsertEventViewModel(application: Application) : AndroidViewModel(application) { 18 | private val contactsRepository = ContactsRepository() 19 | 20 | private val _contactsList = MutableLiveData>(emptyList()) 21 | 22 | // Don't expose the Mutable version explicitly 23 | val contactsList: LiveData> = _contactsList 24 | 25 | @SuppressLint("MissingPermission") 26 | fun initContactsList(act: MainActivity) { 27 | if (act.askContactsPermission()) { 28 | 29 | val resolver = getApplication().contentResolver 30 | viewModelScope.launch { 31 | val contacts = withContext(Dispatchers.IO) { 32 | contactsRepository.queryContacts(resolver) 33 | } 34 | _contactsList.postValue(contacts) 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/widgets/EventWidgetProvider.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.widgets 2 | 3 | import android.appwidget.AppWidgetManager 4 | import android.content.ComponentName 5 | import android.content.Context 6 | import android.content.Intent 7 | import com.minar.birday.R 8 | 9 | 10 | class EventWidgetProvider : BirdayWidgetProvider() { 11 | 12 | override var widgetLayout 13 | get() = R.layout.widget_upcoming 14 | set(_) { 15 | R.layout.widget_upcoming 16 | } 17 | 18 | override fun onReceive(context: Context, intent: Intent) { 19 | val action = intent.action 20 | if (action.equals(AppWidgetManager.ACTION_APPWIDGET_UPDATE)) { 21 | val mgr = AppWidgetManager.getInstance(context) 22 | val cn = ComponentName(context, EventWidgetProvider::class.java) 23 | mgr.getAppWidgetIds(cn).forEach { appWidgetId -> 24 | updateAppWidget(context, mgr, appWidgetId) 25 | } 26 | } 27 | super.onReceive(context, intent) 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/minar/birday/widgets/MinimalWidgetProvider.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.widgets 2 | 3 | import android.appwidget.AppWidgetManager 4 | import android.content.ComponentName 5 | import android.content.Context 6 | import android.content.Intent 7 | import com.minar.birday.R 8 | 9 | 10 | class MinimalWidgetProvider : BirdayWidgetProvider() { 11 | 12 | override var widgetLayout 13 | get() = R.layout.widget_minimal 14 | set(_) { 15 | R.layout.widget_minimal 16 | } 17 | 18 | override fun onReceive(context: Context, intent: Intent) { 19 | val action = intent.action 20 | if (action.equals(AppWidgetManager.ACTION_APPWIDGET_UPDATE)) { 21 | val mgr = AppWidgetManager.getInstance(context) 22 | val cn = ComponentName(context, MinimalWidgetProvider::class.java) 23 | mgr.getAppWidgetIds(cn).forEach { appWidgetId -> 24 | updateAppWidget(context, mgr, appWidgetId) 25 | } 26 | } 27 | super.onReceive(context, intent) 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/nav_enter_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/nav_enter_secondary_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 18 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/anim/nav_exit_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/anim/nav_exit_secondary_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/anim/nav_pop_enter_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/nav_pop_enter_secondary_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/anim/nav_pop_exit_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/anim/nav_pop_exit_secondary_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 18 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/birday_minimal_widget_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/birday_minimal_widget_preview.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/birday_widget_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/birday_widget_preview.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_angry_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_angry_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_angry_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_angry_10.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_angry_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_angry_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_angry_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_angry_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_angry_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_angry_4.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_angry_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_angry_5.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_angry_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_angry_6.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_angry_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_angry_7.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_angry_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_angry_8.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_angry_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_angry_9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_eye_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_eye_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_eye_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_eye_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_eye_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_eye_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_eye_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_eye_4.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_eye_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_eye_5.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_eye_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_eye_6.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_wing_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_wing_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_wing_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_wing_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_wing_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_wing_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_wing_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_wing_4.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_wing_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_wing_5.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_wing_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_wing_6.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_wing_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_wing_7.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/icon_birday_wing_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/icon_birday_wing_8.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/slide_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/slide_one.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/slide_three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/slide_three.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/slide_two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/drawable-nodpi/slide_two.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/animated_angry_notification_icon.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/birday_logo.xml: -------------------------------------------------------------------------------- 1 | 8 | 14 | 18 | 19 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/birday_logo_mono.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bottom_navbar_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/colored_shadow_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_cursor.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_bg_monet.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_alert_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_anniversary_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_app_behavior_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_apps_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_apps_dialer_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_apps_email_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_apps_messages_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_apps_messenger_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_apps_signal_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_apps_telegram_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_apps_threema_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_apps_whatsapp_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_left_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_right_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_up_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_backup_restore_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_balloon_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_clear_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_cool_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_customization_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_date_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_date_question_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_death_anniversary_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_dot_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_dot_small_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_edit_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_event_type_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_favorites_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_github_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_instagram_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_inverted_circle_foreground_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_minar_logo_24dp.xml: -------------------------------------------------------------------------------- 1 | 8 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_name_day_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_neutral_72dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_note_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_note_missing_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notifications_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_octagram_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_other_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_party_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_party_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_pen_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_person_search_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_play_store_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_ring_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sad_72dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_share_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_smile_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_star_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_stats_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_translate_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_triangle_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_troubleshoot_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_aquarius.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_aries.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_cancer.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_capricorn.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_gemini.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_leo.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_libra.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_pisces.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_sagittarius.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_scorpio.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_taurus.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zodiac_virgo.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/line.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/nav_animation_favorites.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/nav_animation_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/nav_animation_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/placeholder_anniversary_image.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 15 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/placeholder_birthday_image.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 15 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/placeholder_death_image.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 15 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/placeholder_name_day_image.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 15 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/placeholder_other_image.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 15 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/scroll_line_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/scroll_thumb_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/snackbar_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/static_birday_dark.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/static_birday_light.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/static_branding_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/static_notification_icon.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/thumb.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/time_picker_chip_background_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/time_picker_chip_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/widget_inner_rounded_container.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/add_demo_entries_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/birday_export_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/birday_import_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/calendar_export_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 26 | 27 | 34 | 35 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/calendar_import_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 26 | 27 | 34 | 35 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/clear_db_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/contacts_import_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 26 | 27 | 34 | 35 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/csv_export_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/csv_import_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_notes.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/disable_optimizations_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/event_type_list_item.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/main/res/layout/json_export_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/json_import_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/missed_carousel_item.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | 19 | 26 | 27 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/month_header_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/layout/notification_sound_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/preference_switch_widget.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/time_picker_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/menu/navigation_bottomappbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | 22 | 23 | 30 | 31 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/raw/birday_notification.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/app/src/main/res/raw/birday_notification.mp3 -------------------------------------------------------------------------------- /app/src/main/res/resources.properties: -------------------------------------------------------------------------------- 1 | unqualifiedResLocale=en-US -------------------------------------------------------------------------------- /app/src/main/res/values-night-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values-v27/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values-v31/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | @string/system_theme 6 | @string/aqua 7 | @string/brown 8 | @string/blue 9 | @string/green 10 | @string/orange 11 | @string/yellow 12 | @string/teal 13 | @string/violet 14 | @string/pink 15 | @string/light_blue 16 | @string/red 17 | @string/lime 18 | @string/crimson 19 | 20 | 21 | 22 | system 23 | aqua 24 | brown 25 | blue 26 | green 27 | orange 28 | yellow 29 | teal 30 | violet 31 | pink 32 | lightBlue 33 | red 34 | lime 35 | crimson 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/values-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/values-v32/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | @string/monet 6 | @string/system_theme 7 | @string/aqua 8 | @string/brown 9 | @string/blue 10 | @string/green 11 | @string/orange 12 | @string/yellow 13 | @string/teal 14 | @string/violet 15 | @string/pink 16 | @string/light_blue 17 | @string/red 18 | @string/lime 19 | @string/crimson 20 | 21 | 22 | 23 | monet 24 | system 25 | aqua 26 | brown 27 | blue 28 | green 29 | orange 30 | yellow 31 | teal 32 | violet 33 | pink 34 | lightBlue 35 | red 36 | lime 37 | crimson 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 13 | 16 | 17 | 18 | 21 | 24 | 27 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/xml/filepaths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/xml/fragment_favorites_scene.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 37 | 38 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/xml/fragment_home_scene.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 44 | 45 | 54 | 55 | 56 | 59 | 60 | 61 | 62 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/src/main/res/xml/widget_minimal_info.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/xml/widget_upcoming_info.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/test/java/com/minar/birday/utils/ChineseCalendarUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.minar.birday.utils 2 | 3 | import com.ibm.icu.util.* 4 | import com.minar.birday.utilities.CalendarAdapter 5 | import com.minar.birday.utilities.chineseAnimalGeneric 6 | import org.junit.Assert.assertEquals 7 | import org.junit.Test 8 | import java.time.LocalDate 9 | 10 | 11 | // Implementation of calendar adapter for original ICU 12 | class ICUCalendar(private val calendar: Calendar): CalendarAdapter { 13 | override fun setTimeInMillis(value: Long) { 14 | calendar.timeInMillis = value 15 | } 16 | 17 | override fun get(field: Int): Int = calendar.get(field) 18 | } 19 | 20 | fun chineseAnimalTest(date: LocalDate): Int = chineseAnimalGeneric( 21 | getChinese = { ICUCalendar(ChineseCalendar()) }, 22 | date 23 | ) 24 | 25 | class ChineseAnimalUnitTest { 26 | // 2020 is the year of the Rat (0) 27 | // However, it started on January 25th, so January 10 is still in the year of the Pig (11) 28 | 29 | @Test 30 | fun chineseAnimal_is_pig_2020_early_January() { 31 | assertEquals(11, chineseAnimalTest(LocalDate.of(2020, 1, 20))) 32 | } 33 | 34 | @Test 35 | fun chineseAnimal_is_rat_2020_late_January() { 36 | assertEquals(0, chineseAnimalTest(LocalDate.of(2020, 1, 28))) 37 | } 38 | 39 | @Test 40 | fun chineseAnimal_is_rat_2020_June() { 41 | assertEquals(0, chineseAnimalTest(LocalDate.of(2020, 6, 1))) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | id("com.android.application") version "8.5.2" apply false 4 | id("org.jetbrains.kotlin.android") version "2.0.0" apply false 5 | id("com.google.devtools.ksp") version "2.0.0-1.0.22" apply false 6 | id("androidx.navigation.safeargs.kotlin") version "2.8.0-beta07" apply false 7 | } -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: app/src/main/res/values/strings.xml 3 | translation: /app/src/main/res/values-%android_code%/strings.xml 4 | translate_attributes: 0 5 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/10.txt: -------------------------------------------------------------------------------- 1 | - Animated notification icon 2 | - Many graphic improvements 3 | - Russian translation, thanks koterpillar 4 | - Under the hood improvements 5 | - Less annoying permission related toast messages 6 | - Fixed some typos -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/11.txt: -------------------------------------------------------------------------------- 1 | - Option to enable the dark theme for the widget 2 | - Czech translation, thanks Miloš Koliáš 3 | - Easily hide and show the top cards with a beautiful animation, to fully support multiwindows 4 | - Every favorite event has now an handy note field, just tap on it!* 5 | - Animated event counter in the stats dialog 6 | - App size shrinked even more! 7 | - New and updated splashscreen animation 8 | - A lot of under the hood improvements and fixes 9 | 10 | * Despite this new field, the previous backups will still work and restore without any problem! -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/13.txt: -------------------------------------------------------------------------------- 1 | - Fixed an important bug involving leap years 2 | - Notes improved, an icon is shown if the event has a note 3 | - Decreased widget minimum size, improved update behavior 4 | - Emoji allowed in name and last name fields 5 | - Long press on the round buttons when the card is hidden to open the corresponding menu 6 | - Portuguese translation, typos fixed 7 | - Other fixes and improvements -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/14.txt: -------------------------------------------------------------------------------- 1 | - Images are now fully supported in notifications, details and events 2 | - Option to disable the Images 3 | - Option to send the notification only for favorite events 4 | - Show last name in notification 5 | - New details screen, new animations 6 | - New and smarter datepicker (supports years from 1500 and keyboard) 7 | - Confetti effect the day of the event 8 | - New (now default) aqua accent 9 | - Better navigation (animations, flow) 10 | - Better backup validation 11 | - Easily revert an event deletion 12 | - A lot (i mean, seriously) of visual improvements 13 | - Many crashes and performance issues were fixed 14 | - Romanian and brazilian translations, portuguese, english, french, german and spanish updated 15 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/15.txt: -------------------------------------------------------------------------------- 1 | - Choose any notification time you want, thanks to the new timepicker! 2 | - Fixed an important time zone related bug 3 | - Some UI improvements 4 | - Traditional chinese translation, updated other languages -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/19.txt: -------------------------------------------------------------------------------- 1 | - Material You! Now Birday uses the latest design guidelines 2 | - Support for anniversaries, death anniversaries and more 3 | - Quick glance 10 days view in the stats card 4 | - Edit the notes from the details page 5 | - System accent color (Android 12+) 6 | - New splashscreen 7 | - New translations, previous translations updated 8 | - Many fixes 9 | - Various UI improvements -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/20.txt: -------------------------------------------------------------------------------- 1 | - Shortcut to disable battery optimizations 2 | - Shortcut to change notification sound 3 | - New animation and icon for name days 4 | - Search improved and fixed 5 | - Optimizations for small screens/ big text sizes 6 | - Other important fixes and improvements -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/21.txt: -------------------------------------------------------------------------------- 1 | - New list to detail transition 2 | - Splashscreen improved 3 | - Important fixes 4 | - Translations updated -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/23.txt: -------------------------------------------------------------------------------- 1 | - New full Material 3 UI 2 | - New full Material 3 widget 3 | - The widget features a list of all the events 4 | - Experimental settings (import/export CSV, import/export JSON, delete all events, hide on scroll, auto import from contacts at launch) 5 | - Android 13 specific features (monochrome icon, per app language support) 6 | - Dates from year 0 to tomorrow supported 7 | - Almost every single icon is animated now 8 | - New animated type selector to filter the events by type 9 | - New yearly overview screen 10 | - Many optimizations 11 | - A lot of bugs fixed 12 | - New languages supported 13 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/25.txt: -------------------------------------------------------------------------------- 1 | - The old widget is back, and is now customizable 2 | - New experimental settings (Angry Bird mode, delete search results) 3 | - Additional notification up to 21 days before 4 | - Choose to send the additional notification only for favorite contacts 5 | - Import the events in your calendar 6 | - More UI improvements, translate the app button 7 | - Translations updated and many bugs fixed -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/26.txt: -------------------------------------------------------------------------------- 1 | - Other options and preview for the minimal widget 2 | - Advanced overview mode 3 | - UI Improvements 4 | - New list animations and transitions 5 | - Some fixes, including a better contacts import 6 | - Many translations updated -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/27.txt: -------------------------------------------------------------------------------- 1 | - Other options and preview for the minimal widget 2 | - Advanced overview mode 3 | - UI Improvements 4 | - New list animations and transitions 5 | - Some fixes, including a better contacts import 6 | - Many translations updated -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/31.txt: -------------------------------------------------------------------------------- 1 | - Black Amoled theme, UI improvements 2 | - Multiple additional notifications 3 | - Group or ungroup notifications 4 | - Disable animation looping 5 | - Display the events in alphabetical order 6 | - Selectable conflict strategy when importing 7 | - Android 14 predictive back 8 | - Rearranged the settings 9 | - Demo elements DB, for testing purposes 10 | - New translations, translations updated 11 | - Many fixes and much more! -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/33.txt: -------------------------------------------------------------------------------- 1 | - Many important fixes (csv import for example) 2 | - Recently missed events in quick apps dialog 3 | - Auto export (experimental) 4 | - Export to calendar (experimental, long press to delete local calendar) 5 | - New translations and more! -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/8.txt: -------------------------------------------------------------------------------- 1 | - Added vietnamese translation 2 | - Notifications improved 3 | - Icon restyled 4 | - Some important fixes -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/9.txt: -------------------------------------------------------------------------------- 1 | - Create yearless events 2 | - The yearless events imported will remain yearless 3 | - Surname first option 4 | - The favorite screen has now a better layout and a countdown for each event! 5 | - Unified details and actions screen: simply tap an event to open it 6 | - Share an event: tap the share button to share a message containing the information about the event! 7 | - Celebrating 1500 Play Store downloads with a new accent color 8 | - Some important fixes and improvements 9 | - Translations updated -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 |

Introduction 👋

2 | This app was created to remember and manage events in a simple and effective way. 3 | The app contains some basic personalization options and an introduction, plus some new resources like animated vector drawables and the automatic dark/light theme. Support and updates are guaranteed! 4 | 5 | 6 |

Why should i use Birday? 😕

7 | Well, i'll tell you 3 main reasons: 8 |
    9 |
  • It can help you to remember every birthday in the moment you prefer!
  • 10 |
  • It will cost just a few MB of storage!
  • 11 |
  • It's beautiful, full of animations and simple to use!
  • 12 |
13 | 14 | Birday allows you to import the events directly from your contacts or calendar, with a simple favorite system and a set of stats to discover! 15 | if you're starting to develop apps and you need an app to look at, to find some inspiration and tricks: click on the Github link, and the Birday source code is served! 16 | 17 | 18 |

Features 🎂

19 |
    20 |
  • Simple events timeline, with the next date and the name of each person
  • 21 |
  • Favorite system, to aggregate your favorite events and see more information
  • 22 |
  • Overview screen and a lot of basic and advanced settings
  • 23 |
  • Import birthdays from contacts or calendar with basic duplicate detection
  • 24 |
  • Backup your events easily, in native, csv or json format 25 |
  • 30+ language available. If you don't see your language, you can translate the app yourself!
  • 26 |
  • Easily delete, modify or share every event
  • 27 |
  • Each favorite event has an handy note field
  • 28 |
  • Customizable notification the day of the event, and additional notification(s)!
  • 29 |
  • Light, dark and black Amoled theme
  • 30 |
  • Selectable accent and Monet accent (12 choices)
  • 31 |
  • Hide and unhide the top cards for maximum ui flexibility
  • 32 |
  • A quick search bar and type selector!
  • 33 |
  • 2 customizable widgets
  • 34 |
  • First introduction and beautiful animations including an animated notification icon
  • 35 |
  • Simple and precise ui, following the material guidelines
  • 36 |
37 | 38 | Please note: the notification system relies on the Android OS resources, thus some manufacturers may cause malfunctions. The reason is that some Xiaomi, Huawei and Oneplus devices kill the apps instead of simply closing it, or block the automatic startup of the app process. I can't fix this, but you can find more information on dontkillmyapp.com. 39 | 40 | 41 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/featureGraphic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/featureGraphic.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/icon.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/phoneScreenshots/01.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/phoneScreenshots/02.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/phoneScreenshots/03.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/phoneScreenshots/04.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/phoneScreenshots/05.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/phoneScreenshots/06.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/phoneScreenshots/07.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/phoneScreenshots/08.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/phoneScreenshots/09.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/fastlane/metadata/android/en-US/images/phoneScreenshots/10.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | A simple yet useful birthday manager. Birday is free and ad-free! 🥳 -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/title.txt: -------------------------------------------------------------------------------- 1 | Birday - Birthday Manager -------------------------------------------------------------------------------- /fastlane/metadata/android/fr-FR/short_description.txt: -------------------------------------------------------------------------------- 1 | Un gestionnaire d'anniversaire simple et utile. Birday est gratuit et sans publicité! 🥳 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/fr-FR/title.txt: -------------------------------------------------------------------------------- 1 | Birday - Gestionnaire d'anniversaires 2 | -------------------------------------------------------------------------------- /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 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | android.nonTransitiveRClass=false 23 | # Generate compile-time only R class for app modules 24 | android.enableAppCompileTimeRClass=true 25 | # Only keep the single relevant constructor for types mentioned in XML files 26 | # instead of using a parameter wildcard which keeps them all 27 | android.useMinimalKeepRules=true 28 | # Enable resource optimizations for release build 29 | android.enableResourceOptimizations=true 30 | # Gradle 31 | org.gradle.caching=true 32 | org.gradle.configureondemand=true 33 | # Use R8 in full mode instead of ProGuard compatibility mode. 34 | android.enableR8.fullMode=true 35 | # Build BuildConfig as Bytecode 36 | android.enableBuildConfigAsBytecode=true 37 | # Suppress unsupported CompileSdk warning 38 | android.suppressUnsupportedCompileSdk=35 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-i-n-a-r/birday/96c5c48f3c26c91bdfaa614c9b836370a09647df/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /scripts/check_translate_missing_strings.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | FOLDER_TO_CHECK="${1}" 4 | 5 | ################################################################################ 6 | gather_main_strings() { 7 | local strings_main_file="app/src/main/res/values/strings.xml" 8 | 9 | STRINGS_MAIN=$(grep "name=" "${strings_main_file}" | \ 10 | grep -v "translatable" | cut -d '"' -f2) 11 | } 12 | 13 | gather_strings_to_be_translated() { 14 | local strings_to_check_file="app/src/main/res/${FOLDER_TO_CHECK}/strings.xml" 15 | 16 | # Check if file exists, exit otherwise 17 | if [ ! -f "${strings_to_check_file}" ]; then 18 | echo "Folder pattern should look like 'values-'" 19 | echo "File ($strings_to_check_file) does not exist, exiting..." 20 | exit 1 21 | fi 22 | 23 | STRINGS_TO_CHECK=$(grep "name=" "${strings_to_check_file}" | \ 24 | grep -v "translatable" | cut -d '"' -f2) 25 | } 26 | ################################################################################ 27 | 28 | gather_main_strings 29 | gather_strings_to_be_translated 30 | 31 | echo "The missing strings on ${FOLDER_TO_CHECK} are: " 32 | echo "${STRINGS_MAIN[@]}" "${STRINGS_TO_CHECK[@]}" | \ 33 | tr ' ' '\n' | sort | uniq -u 34 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | pluginManagement { 4 | repositories { 5 | gradlePluginPortal() 6 | google() 7 | mavenCentral() 8 | } 9 | } 10 | 11 | dependencyResolutionManagement { 12 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 13 | repositories { 14 | google() 15 | mavenCentral() 16 | maven("https://jitpack.io") 17 | } 18 | } 19 | 20 | plugins { 21 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" 22 | } 23 | 24 | rootProject.name = "Birday" 25 | include(":app") --------------------------------------------------------------------------------