├── git ├── app ├── .gitignore ├── src │ ├── main │ │ ├── ic_launcher-web.png │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── icon.png │ │ │ │ ├── avatar.png │ │ │ │ ├── icon_background.png │ │ │ │ ├── icon_foreground.png │ │ │ │ ├── normal_mode_simple.png │ │ │ │ ├── period_mode_simple.png │ │ │ │ ├── custom_counter_bg.xml │ │ │ │ ├── custom_selected_item_bg.xml │ │ │ │ ├── custom_detail_color.xml │ │ │ │ ├── custom_edit_text_color.xml │ │ │ │ ├── ic_line.xml │ │ │ │ ├── custom_swipe_bg_red.xml │ │ │ │ ├── custom_swipe_bg_yellow.xml │ │ │ │ ├── custom_checkbox.xml │ │ │ │ ├── custom_item_bg.xml │ │ │ │ ├── ic_expand_more.xml │ │ │ │ ├── ic_drop_down.xml │ │ │ │ ├── ic_title.xml │ │ │ │ ├── ic_add.xml │ │ │ │ ├── ic_dot.xml │ │ │ │ ├── ic_circle.xml │ │ │ │ ├── ic_done.xml │ │ │ │ ├── ic_expand_less.xml │ │ │ │ ├── ic_back.xml │ │ │ │ ├── ic_drawer.xml │ │ │ │ ├── ic_hide_show_completed_events.xml │ │ │ │ ├── ic_creation_date.xml │ │ │ │ ├── ic_ongoing.xml │ │ │ │ ├── ic_close.xml │ │ │ │ ├── ic_code.xml │ │ │ │ ├── ic_waiting.xml │ │ │ │ ├── ic_checked.xml │ │ │ │ ├── ic_priority_low.xml │ │ │ │ ├── ic_unchecked.xml │ │ │ │ ├── ic_completed.xml │ │ │ │ ├── ic_gone.xml │ │ │ │ ├── ic_edit.xml │ │ │ │ ├── ic_completed_events.xml │ │ │ │ ├── ic_sort_circle.xml │ │ │ │ ├── ic_alpha.xml │ │ │ │ ├── ic_delete.xml │ │ │ │ ├── ic_delete_dark.xml │ │ │ │ ├── custom_ripple.xml │ │ │ │ ├── ic_hourglass_end.xml │ │ │ │ ├── ic_hourglass_start.xml │ │ │ │ ├── ic_start.xml │ │ │ │ ├── ic_add_category.xml │ │ │ │ ├── ic_translate.xml │ │ │ │ ├── ic_help.xml │ │ │ │ ├── ic_today.xml │ │ │ │ ├── ic_licenses.xml │ │ │ │ ├── ic_feedback.xml │ │ │ │ ├── ic_category_circle.xml │ │ │ │ ├── ic_priority_medium.xml │ │ │ │ ├── ic_stars.xml │ │ │ │ ├── custom_event_progress.xml │ │ │ │ ├── ic_next_7_days.xml │ │ │ │ ├── ic_durable_event.xml │ │ │ │ ├── ic_inbox.xml │ │ │ │ ├── ic_notification.xml │ │ │ │ ├── ic_sort.xml │ │ │ │ ├── ic_sort_swap.xml │ │ │ │ ├── ic_reminder.xml │ │ │ │ ├── ic_introduction.xml │ │ │ │ ├── ic_priority_high.xml │ │ │ │ ├── ic_category.xml │ │ │ │ ├── ic_gift.xml │ │ │ │ ├── ic_about.xml │ │ │ │ ├── ic_notes.xml │ │ │ │ ├── ic_all_events.xml │ │ │ │ ├── ic_manage_categories.xml │ │ │ │ ├── ic_settings.xml │ │ │ │ ├── ils_morning.xml │ │ │ │ └── ils_noon.xml │ │ │ ├── font │ │ │ │ └── noto_sans.ttf │ │ │ ├── drawable-hdpi │ │ │ │ ├── top.png │ │ │ │ ├── empty_hourglass.png │ │ │ │ └── introduction_1.png │ │ │ ├── drawable-mdpi │ │ │ │ ├── top.png │ │ │ │ ├── empty_hourglass.png │ │ │ │ └── introduction_1.png │ │ │ ├── drawable-xhdpi │ │ │ │ ├── top.png │ │ │ │ ├── introduction_1.png │ │ │ │ └── empty_hourglass.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── top.png │ │ │ │ ├── empty_hourglass.png │ │ │ │ └── introduction_1.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ ├── top.png │ │ │ │ ├── empty_hourglass.png │ │ │ │ └── introduction_1.png │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── anim │ │ │ │ ├── layout_fall_down.xml │ │ │ │ ├── slide_in_right.xml │ │ │ │ ├── slide_out_left.xml │ │ │ │ ├── fade_out.xml │ │ │ │ ├── slide_in_left.xml │ │ │ │ ├── slide_out_right.xml │ │ │ │ ├── icon_anim.xml │ │ │ │ ├── scale_from_fab.xml │ │ │ │ ├── item_fall_down.xml │ │ │ │ └── fade_in.xml │ │ │ ├── color │ │ │ │ ├── primary_text_color.xml │ │ │ │ └── secondary_text_color.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ ├── item_category_select.xml │ │ │ │ ├── item_simple_choice.xml │ │ │ │ ├── dialog_simple_choice.xml │ │ │ │ ├── dialog_date.xml │ │ │ │ ├── item_custom_category.xml │ │ │ │ ├── navigation_activity.xml │ │ │ │ ├── fragment_custom_categories.xml │ │ │ │ ├── item_drawer.xml │ │ │ │ ├── dialog_category_edit.xml │ │ │ │ ├── manage_categories_fragment.xml │ │ │ │ ├── dialog_category_select.xml │ │ │ │ ├── introduction_feature_1.xml │ │ │ │ ├── fragment_introduction.xml │ │ │ │ ├── introduction_welcome.xml │ │ │ │ ├── dialog_licenses.xml │ │ │ │ └── dialog_about_durable_event.xml │ │ │ ├── menu │ │ │ │ ├── menu_edit.xml │ │ │ │ ├── menu_task_detail.xml │ │ │ │ ├── menu_events.xml │ │ │ │ └── menu_reminder_units.xml │ │ │ ├── values │ │ │ │ ├── arrays.xml │ │ │ │ ├── dimens.xml │ │ │ │ └── colors.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── navigation │ │ │ │ └── navigation.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── gwokhou │ │ │ │ └── deadline │ │ │ │ ├── TimerUpdateListener.java │ │ │ │ ├── events │ │ │ │ ├── BackPressedHandler.java │ │ │ │ ├── item │ │ │ │ │ ├── EventItemActionListener.java │ │ │ │ │ ├── EventTouchHelperListener.java │ │ │ │ │ └── EventTouchHelperCallback.java │ │ │ │ ├── drawer │ │ │ │ │ └── DrawerItemActionListener.java │ │ │ │ └── UpdateEventsDataListener.java │ │ │ │ ├── categorySelector │ │ │ │ ├── CategoryItemActionListener.java │ │ │ │ ├── CategoriesLoadedListener.java │ │ │ │ ├── CategorySelectDialogViewModel.java │ │ │ │ └── CategoryAdapter.java │ │ │ │ ├── manageCategories │ │ │ │ ├── custom │ │ │ │ │ ├── CustomCategoryItemActionListener.java │ │ │ │ │ ├── CustomCategoriesAdapter.java │ │ │ │ │ └── CustomCategoriesViewModel.java │ │ │ │ ├── ManageCategoriesPagerAdapter.java │ │ │ │ ├── smart │ │ │ │ │ ├── SmartCategoriesViewModel.java │ │ │ │ │ └── SmartCategoriesFragment.java │ │ │ │ └── ManageCategoriesFragment.java │ │ │ │ ├── sort │ │ │ │ ├── SortItemActionListener.java │ │ │ │ └── SortBottomSheetFragment.java │ │ │ │ ├── dataType │ │ │ │ ├── QuickViewBehType.java │ │ │ │ ├── PriorityType.java │ │ │ │ ├── StateType.java │ │ │ │ ├── SortType.java │ │ │ │ ├── FilterType.java │ │ │ │ └── RemindType.java │ │ │ │ ├── settings │ │ │ │ ├── SettingItemActionListener.java │ │ │ │ └── SettingsViewModel.java │ │ │ │ ├── editEvent │ │ │ │ └── EditActionListener.java │ │ │ │ ├── data │ │ │ │ ├── DrawerItem.java │ │ │ │ ├── EventDataSource.java │ │ │ │ ├── CategoriesDao.java │ │ │ │ ├── CategoryDataSource.java │ │ │ │ ├── Category.java │ │ │ │ ├── DeadlineDatabase.java │ │ │ │ ├── EventsDao.java │ │ │ │ ├── Event.java │ │ │ │ └── CategoryLocalDataSource.java │ │ │ │ ├── util │ │ │ │ ├── DiskIOThreadExecutor.java │ │ │ │ ├── StartIntentUtils.java │ │ │ │ ├── ReminderUtils.java │ │ │ │ ├── SnackbarUtils.java │ │ │ │ ├── UpdateSelectedCategoryPreferences.java │ │ │ │ ├── DataBindingAdapters.java │ │ │ │ ├── DonateUtils.java │ │ │ │ ├── SortUtils.java │ │ │ │ ├── FilterUtils.java │ │ │ │ ├── SystemUIUtils.java │ │ │ │ ├── AppExecutors.java │ │ │ │ └── ResourceValueUtils.java │ │ │ │ ├── view │ │ │ │ └── TimerView.java │ │ │ │ ├── intro │ │ │ │ └── IntroPagerAdapter.java │ │ │ │ ├── ReminderReceiver.java │ │ │ │ ├── SnackbarMessage.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── fragments │ │ │ │ ├── TypeTipsDialogFragment.java │ │ │ │ └── SimpleAlertDialogFragment.java │ │ │ │ ├── SingleLiveEvent.java │ │ │ │ └── reminderSelect │ │ │ │ └── ReminderDialogViewModel.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── gwokhou │ │ │ └── deadline │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── gwokhou │ │ └── deadline │ │ └── ExampleInstrumentedTest.java ├── release │ └── output.json ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── pic ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── ic.png ├── preview_1.jpg └── preview_2.jpg ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties ├── README.md └── gradlew.bat /git: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /pic/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/pic/1.png -------------------------------------------------------------------------------- /pic/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/pic/2.png -------------------------------------------------------------------------------- /pic/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/pic/3.png -------------------------------------------------------------------------------- /pic/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/pic/4.png -------------------------------------------------------------------------------- /pic/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/pic/5.png -------------------------------------------------------------------------------- /pic/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/pic/6.png -------------------------------------------------------------------------------- /pic/ic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/pic/ic.png -------------------------------------------------------------------------------- /pic/preview_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/pic/preview_1.jpg -------------------------------------------------------------------------------- /pic/preview_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/pic/preview_2.jpg -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable/icon.png -------------------------------------------------------------------------------- /app/src/main/res/font/noto_sans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/font/noto_sans.ttf -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-hdpi/top.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-mdpi/top.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable/avatar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-xhdpi/top.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-xxhdpi/top.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-xxxhdpi/top.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable/icon_background.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable/icon_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/normal_mode_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable/normal_mode_simple.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/period_mode_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable/period_mode_simple.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/empty_hourglass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-hdpi/empty_hourglass.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/introduction_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-hdpi/introduction_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/empty_hourglass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-mdpi/empty_hourglass.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/introduction_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-mdpi/introduction_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/introduction_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-xhdpi/introduction_1.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/empty_hourglass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-xhdpi/empty_hourglass.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/empty_hourglass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-xxhdpi/empty_hourglass.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/introduction_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-xxhdpi/introduction_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/empty_hourglass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-xxxhdpi/empty_hourglass.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/introduction_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/drawable-xxxhdpi/introduction_1.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gwokhov/Deadline/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea 5 | .DS_Store 6 | /build 7 | app/release 8 | *.apk 9 | /captures 10 | .externalNativeBuild 11 | /.idea 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/TimerUpdateListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline; 2 | 3 | public interface TimerUpdateListener { 4 | 5 | void onUpdateView(long duration); 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/events/BackPressedHandler.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.events; 2 | 3 | public interface BackPressedHandler { 4 | void setSelectedFragment(EventsFragment fragment); 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/events/item/EventItemActionListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.events.item; 2 | 3 | public interface EventItemActionListener { 4 | 5 | void onItemClicked(String eventId); 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/events/drawer/DrawerItemActionListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.events.drawer; 2 | 3 | public interface DrawerItemActionListener { 4 | 5 | void onItemClicked(String type); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/categorySelector/CategoryItemActionListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.categorySelector; 2 | 3 | public interface CategoryItemActionListener { 4 | 5 | void onItemClicked(String category); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_counter_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":6,"versionName":"1.0 beta06","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/manageCategories/custom/CustomCategoryItemActionListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.manageCategories.custom; 2 | 3 | public interface CustomCategoryItemActionListener { 4 | 5 | void onItemClicked(String id); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_selected_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/sort/SortItemActionListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.sort; 2 | 3 | public interface SortItemActionListener { 4 | 5 | void onItemClicked(int type); 6 | 7 | void onSwitchedSortOrder(boolean isAsc); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/layout_fall_down.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 07 14:30:19 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_detail_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_edit_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/events/UpdateEventsDataListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.events; 2 | 3 | public interface UpdateEventsDataListener { 4 | 5 | void onSortUpdate(int type); 6 | 7 | void onIsAscUpdate(boolean isAsc); 8 | 9 | void onEventDelete(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/events/item/EventTouchHelperListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.events.item; 2 | 3 | public interface EventTouchHelperListener { 4 | 5 | // void onItemMove(int formPosition, int toPosition); 6 | 7 | void onItemSwipeToStart(int position); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/dataType/QuickViewBehType.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.dataType; 2 | 3 | public class QuickViewBehType { 4 | 5 | public static final int SHOW_WHEN_OPEN = 0; 6 | // public static final int SHOW_PER_DAY = 1; 7 | public static final int STICKY = 1; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/res/color/primary_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_line.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/settings/SettingItemActionListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.settings; 2 | 3 | public interface SettingItemActionListener { 4 | 5 | void onStartOfWeekClicked(); 6 | 7 | void onDailyReminderClicked(); 8 | 9 | void onQuickViewBehaviorClicked(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/color/secondary_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/dataType/PriorityType.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.dataType; 2 | 3 | public class PriorityType { 4 | 5 | public static final int NONE = 0; 6 | public static final int LOW = 1; 7 | public static final int MEDIUM = 2; 8 | public static final int HIGH = 3; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/dataType/StateType.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.dataType; 2 | 3 | public class StateType { 4 | 5 | public static final int GONE = 0; 6 | public static final int ONGOING = 1; 7 | public static final int WAITING = 2; 8 | public static final int COMPLETED = 3; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_category_select.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/dataType/SortType.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.dataType; 2 | 3 | public class SortType { 4 | 5 | public static final int PRIORITY = 0; 6 | public static final int DUE_DATE = 1; 7 | public static final int CREATION_DATE = 2; 8 | public static final int ALPHA = 3; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/categorySelector/CategoriesLoadedListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.categorySelector; 2 | 3 | import com.gwokhou.deadline.data.Category; 4 | 5 | import java.util.List; 6 | 7 | public interface CategoriesLoadedListener { 8 | 9 | void onLoadedFinished(List categories); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_swipe_bg_red.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_swipe_bg_yellow.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_checkbox.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_expand_more.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_simple_choice.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_drop_down.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_title.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_dot.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_circle.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_done.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_expand_less.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_back.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_drawer.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hide_show_completed_events.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_creation_date.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_ongoing.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_code.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/dataType/FilterType.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.dataType; 2 | 3 | public class FilterType { 4 | 5 | public static final String ALL_EVENTS = "ALL_EVENTS"; 6 | public static final String TODAY_EVENTS = "TODAY_EVENTS"; 7 | public static final String NEXT_7_DAYS_EVENTS = "NEXT_7_DAYS_EVENTS "; 8 | public static final String COMPLETED_EVENTS = "COMPLETED_EVENTS"; 9 | public static final String INBOX = "Inbox"; 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/editEvent/EditActionListener.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.editEvent; 2 | 3 | public interface EditActionListener { 4 | 5 | void onCheckBoxClicked(); 6 | 7 | void onTipsClicked(); 8 | 9 | void onStartDateClicked(); 10 | 11 | void onDueDateClicked(); 12 | 13 | void onCategoryClicked(); 14 | 15 | void onPriorityClicked(); 16 | 17 | void onReminderClicked(); 18 | 19 | void onFabClicked(); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_waiting.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_checked.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_priority_low.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/test/java/com/gwokhou/deadline/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_unchecked.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_completed.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_gone.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #00897B 6 | #FDD835 7 | #D32F2F 8 | #2196F3 9 | 10 | 11 | 12 | #1400796B 13 | #0F00796B 14 | #0A00796B 15 | #0500796B 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_edit.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_completed_events.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sort_circle.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_alpha.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/icon_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_dark.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/dataType/RemindType.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.dataType; 2 | 3 | public class RemindType { 4 | 5 | public static final int NONE_REMIND = -1; 6 | 7 | public static final int SINGLE_REMIND = 0; 8 | public static final int SINGLE_DUE_DATE = 1; 9 | public static final int SINGLE_MIN = 2; 10 | public static final int SINGLE_HOUR = 3; 11 | public static final int SINGLE_DAY = 4; 12 | public static final int SINGLE_WEEK = 5; 13 | 14 | public static final int REPEATED_EVERYDAY = 6; 15 | public static final int REPEATED_ALWAYS = 7; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_ripple.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hourglass_end.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hourglass_start.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_start.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_category.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/data/DrawerItem.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.data; 2 | 3 | public class DrawerItem { 4 | 5 | private int mTitleRes; 6 | 7 | private int mIconRes; 8 | 9 | private String mType; 10 | 11 | public DrawerItem(int title, int iconRes, String type) { 12 | mTitleRes = title; 13 | mIconRes = iconRes; 14 | mType = type; 15 | } 16 | 17 | public int getTitleRes() { 18 | return mTitleRes; 19 | } 20 | 21 | public int getIconRes() { 22 | return mIconRes; 23 | } 24 | 25 | public String getType() { 26 | return mType; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_translate.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/DiskIOThreadExecutor.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.util; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.Executors; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | /** 9 | * Executor that runs a task on a new background thread. 10 | */ 11 | public class DiskIOThreadExecutor implements Executor { 12 | 13 | private final Executor mDiskIO; 14 | 15 | public DiskIOThreadExecutor() { 16 | mDiskIO = Executors.newSingleThreadExecutor(); 17 | } 18 | 19 | @Override 20 | public void execute(@NonNull Runnable command) { 21 | mDiskIO.execute(command); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_help.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_today.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_licenses.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_task_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/anim/scale_from_fab.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_feedback.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_category_circle.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_priority_medium.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/StartIntentUtils.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.util; 2 | 3 | import android.app.Activity; 4 | import android.content.ActivityNotFoundException; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | 8 | public class StartIntentUtils { 9 | 10 | public static boolean startIntentUrl(Activity activity, String intentFullUrl) { 11 | try { 12 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(intentFullUrl)); 13 | activity.startActivity(intent); 14 | return true; 15 | } catch (ActivityNotFoundException e) { 16 | e.printStackTrace(); 17 | return false; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_stars.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_events.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/data/EventDataSource.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.data; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | public interface EventDataSource { 6 | 7 | interface GetEventCallback { 8 | 9 | void onEventLoaded(Event event); 10 | 11 | void onDataNotAvailable(); 12 | } 13 | 14 | void getEvent(@NonNull String taskId, @NonNull GetEventCallback callback); 15 | 16 | void saveEvent(@NonNull Event event); 17 | 18 | void updateEventState(@NonNull Event event, int state); 19 | 20 | void updateEventState(@NonNull String taskId, int state); 21 | 22 | void clearCompletedEvents(); 23 | 24 | void deleteAllEvents(); 25 | 26 | void deleteEvent(@NonNull String taskId); 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_simple_choice.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_event_progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_next_7_days.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_durable_event.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_date.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_inbox.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notification.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sort.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/anim/item_fall_down.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 13 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sort_swap.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_custom_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | -------------------------------------------------------------------------------- /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 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reminder.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_introduction.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/gwokhou/deadline/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.InstrumentationRegistry; 6 | import androidx.test.runner.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("com.gwokhou.deadline", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/data/CategoriesDao.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.data; 2 | 3 | import java.util.List; 4 | 5 | import androidx.room.Dao; 6 | import androidx.room.Insert; 7 | import androidx.room.OnConflictStrategy; 8 | import androidx.room.Query; 9 | 10 | @Dao 11 | public interface CategoriesDao { 12 | 13 | @Query("SELECT * FROM category_table") 14 | List getAllCategories(); 15 | 16 | @Query("SELECT * FROM category_table WHERE entry_id = :categoryId") 17 | Category getCategoryById(String categoryId); 18 | 19 | @Insert(onConflict = OnConflictStrategy.REPLACE) 20 | void insertCategory(Category category); 21 | 22 | @Query("DELETE FROM category_table WHERE entry_id = :categoryId") 23 | int deleteCategoryById(String categoryId); 24 | 25 | @Query("DELETE FROM category_table") 26 | void deleteAllCategories(); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_priority_high.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 19 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/data/CategoryDataSource.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.data; 2 | 3 | import java.util.List; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | public interface CategoryDataSource { 8 | 9 | interface LoadCategoriesCallback { 10 | 11 | void onCategoriesLoaded(List categories); 12 | 13 | void onDataNotAvailable(); 14 | 15 | } 16 | 17 | interface GetCategoryCallback { 18 | 19 | void onCategoryLoaded(Category category); 20 | 21 | void onDataNotAvailable(); 22 | 23 | } 24 | 25 | void getAllCategories(@NonNull LoadCategoriesCallback callback); 26 | 27 | void getCategory(@NonNull String categoryId, @NonNull GetCategoryCallback callback); 28 | 29 | void saveCategory(@NonNull Category category); 30 | 31 | void deleteAllCategories(); 32 | 33 | void deleteCategory(@NonNull String categoryId); 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/ReminderUtils.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.util; 2 | 3 | import com.gwokhou.deadline.dataType.RemindType; 4 | 5 | public class ReminderUtils { 6 | 7 | //个位数0代表无重复通知,1代表每天显示,2代表常驻通知栏 8 | //十位数0代表无,1代表分,2代表时,3代表天,4代表月 9 | //间隔单位乘100 10 | 11 | public static int getSingleRemindInterval(int data) { 12 | if (data < 10) { 13 | return RemindType.NONE_REMIND; 14 | } else { 15 | return data / 10; 16 | } 17 | } 18 | 19 | public static int getRemindType(int data) { 20 | return data % 10; 21 | } 22 | 23 | public static int buildReminder(int remindType, int singleRemindInterval) { 24 | if (remindType == RemindType.NONE_REMIND) { 25 | return RemindType.NONE_REMIND; 26 | } else { 27 | return singleRemindInterval * 10 + remindType; 28 | } 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_in.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_category.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/data/Category.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.data; 2 | 3 | import java.util.UUID; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.room.ColumnInfo; 7 | import androidx.room.Entity; 8 | import androidx.room.Ignore; 9 | import androidx.room.PrimaryKey; 10 | 11 | @Entity(tableName = "category_table") 12 | public class Category { 13 | 14 | @PrimaryKey 15 | @NonNull 16 | @ColumnInfo(name = "entry_id") 17 | private String mId; 18 | 19 | @NonNull 20 | @ColumnInfo(name = "name") 21 | private String mName; 22 | 23 | @Ignore 24 | public Category(String name) { 25 | this(name, UUID.randomUUID().toString()); 26 | } 27 | 28 | public Category(String name, String id) { 29 | mName = name; 30 | mId = id; 31 | } 32 | 33 | @NonNull 34 | public String getId() { 35 | return mId; 36 | } 37 | 38 | @NonNull 39 | public String getName() { 40 | return mName; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/navigation_activity.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_reminder_units.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | 22 | 23 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_gift.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/data/DeadlineDatabase.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.data; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.room.Database; 6 | import androidx.room.Room; 7 | import androidx.room.RoomDatabase; 8 | 9 | @Database(entities = {Event.class, Category.class}, version = 2, exportSchema = false) 10 | public abstract class DeadlineDatabase extends RoomDatabase { 11 | 12 | private static DeadlineDatabase INSTANCE; 13 | 14 | public abstract EventsDao eventDao(); 15 | 16 | public abstract CategoriesDao categoriesDao(); 17 | 18 | public static DeadlineDatabase getDatabase(final Context context) { 19 | if (INSTANCE == null) { 20 | synchronized (DeadlineDatabase.class) { 21 | if (INSTANCE == null) { 22 | INSTANCE = Room.databaseBuilder(context.getApplicationContext(), 23 | DeadlineDatabase.class, "event_database.db") 24 | .build(); 25 | } 26 | } 27 | } 28 | return INSTANCE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/manageCategories/ManageCategoriesPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.manageCategories; 2 | 3 | import java.util.List; 4 | 5 | import androidx.fragment.app.Fragment; 6 | import androidx.fragment.app.FragmentManager; 7 | import androidx.fragment.app.FragmentPagerAdapter; 8 | 9 | public class ManageCategoriesPagerAdapter extends FragmentPagerAdapter { 10 | 11 | private List mFragments; 12 | private String[] mTitles; 13 | 14 | public ManageCategoriesPagerAdapter(FragmentManager manager, List list, String[] titles) { 15 | super(manager); 16 | mFragments = list; 17 | mTitles = titles; 18 | } 19 | 20 | @Override 21 | public Fragment getItem(int position) { 22 | return mFragments.get(position); 23 | } 24 | 25 | @Override 26 | public int getCount() { 27 | return mFragments.size(); 28 | } 29 | 30 | // @Nullable 31 | // @Override 32 | // public CharSequence getPageTitle(int position) { 33 | // return mTitles[position]; 34 | // 35 | // } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/data/EventsDao.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.data; 2 | 3 | 4 | import java.util.List; 5 | 6 | import androidx.lifecycle.LiveData; 7 | import androidx.room.Dao; 8 | import androidx.room.Insert; 9 | import androidx.room.OnConflictStrategy; 10 | import androidx.room.Query; 11 | 12 | @Dao 13 | public interface EventsDao { 14 | 15 | @Query("SELECT * FROM event_table") 16 | LiveData> getAllEvents(); 17 | 18 | @Query("SELECT * FROM event_table WHERE entry_id = :eventId") 19 | Event getEventById(String eventId); 20 | 21 | @Insert(onConflict = OnConflictStrategy.REPLACE) 22 | void insertEvent(Event event); 23 | 24 | @Query("UPDATE event_table SET state = :state WHERE entry_id = :eventId") 25 | void updateState(String eventId, int state); 26 | 27 | @Query("DELETE FROM event_table WHERE entry_id = :eventId") 28 | int deleteEventById(String eventId); 29 | 30 | @Query("DELETE FROM event_table") 31 | void deleteAllEvents(); 32 | 33 | @Query("DELETE FROM event_table WHERE state = 4") 34 | int deleteCompletedEvents(); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/view/TimerView.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | 6 | import com.gwokhou.deadline.TimerUpdateListener; 7 | 8 | import cn.iwgang.countdownview.CountdownView; 9 | 10 | public class TimerView extends CountdownView { 11 | private TimerUpdateListener mTimerUpdateListener; 12 | 13 | public TimerView(Context context) { 14 | super(context); 15 | } 16 | 17 | public TimerView(Context context, AttributeSet attrs) { 18 | super(context, attrs); 19 | } 20 | 21 | public TimerView(Context context, AttributeSet attrs, int defStyleAttr) { 22 | super(context, attrs, defStyleAttr); 23 | } 24 | 25 | @Override 26 | public void updateShow(long ms) { 27 | super.updateShow(ms); 28 | 29 | if (mTimerUpdateListener != null) { 30 | mTimerUpdateListener.onUpdateView(ms); 31 | } 32 | } 33 | 34 | public void setTimerUpdateListener(TimerUpdateListener timerUpdateListener) { 35 | mTimerUpdateListener = timerUpdateListener; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_custom_categories.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 23 | 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_about.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/intro/IntroPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.intro; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | 6 | import java.util.List; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.viewpager.widget.PagerAdapter; 10 | 11 | public class IntroPagerAdapter extends PagerAdapter { 12 | 13 | private List mViewList; 14 | 15 | public IntroPagerAdapter(List viewList) { 16 | mViewList = viewList; 17 | } 18 | 19 | @Override 20 | public int getCount() { 21 | return mViewList.size(); 22 | } 23 | 24 | @Override 25 | public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { 26 | return view == object; 27 | } 28 | 29 | @Override 30 | public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { 31 | container.removeView((View) object); 32 | } 33 | 34 | @NonNull 35 | @Override 36 | public Object instantiateItem(@NonNull ViewGroup container, int position) { 37 | container.addView(mViewList.get(position)); 38 | return mViewList.get(position); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/SnackbarUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.gwokhou.deadline.util; 18 | 19 | import android.view.View; 20 | 21 | import com.google.android.material.snackbar.Snackbar; 22 | 23 | /** 24 | * Provides a method to show a Snackbar. 25 | */ 26 | public class SnackbarUtils { 27 | 28 | public static void showSnackbar(View v, String snackbarText) { 29 | if (v == null || snackbarText == null) { 30 | return; 31 | } 32 | Snackbar.make(v, snackbarText, Snackbar.LENGTH_LONG).show(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 21 | 22 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/UpdateSelectedCategoryPreferences.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.util; 2 | 3 | import android.content.Context; 4 | 5 | import com.gwokhou.deadline.AppPreferences; 6 | import com.gwokhou.deadline.dataType.FilterType; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class UpdateSelectedCategoryPreferences { 12 | 13 | public static void updateAppPreferences(Context context) { 14 | List enableCategories = new ArrayList<>(0); 15 | 16 | if (AppPreferences.isShowAllEventsCategory(context)) { 17 | enableCategories.add(FilterType.ALL_EVENTS); 18 | } 19 | 20 | if (AppPreferences.isShowTodayEventsCategory(context)) { 21 | enableCategories.add(FilterType.TODAY_EVENTS); 22 | } 23 | 24 | if (AppPreferences.isShowNext7DaysEventsCategory(context)) { 25 | enableCategories.add(FilterType.NEXT_7_DAYS_EVENTS); 26 | } 27 | 28 | if (AppPreferences.isShowCompletedEventsCategory(context)) { 29 | enableCategories.add(FilterType.COMPLETED_EVENTS); 30 | } 31 | 32 | if (enableCategories.size() != 0) { 33 | AppPreferences.setCurrentCategory(context, enableCategories.get(0)); 34 | } 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notes.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 17 | 20 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_all_events.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/ReminderReceiver.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | 7 | import com.gwokhou.deadline.util.NotificationUtils; 8 | 9 | public class ReminderReceiver extends BroadcastReceiver { 10 | 11 | @Override 12 | public void onReceive(Context context, Intent intent) { 13 | boolean isRepeated = intent.getBooleanExtra(NotificationUtils.EXTRA_IS_REPEATED, false); 14 | 15 | 16 | String notificationTitle = intent.getStringExtra(NotificationUtils.EXTRA_NOTIFICATION_TITLE); 17 | String content = intent.getStringExtra(NotificationUtils.EXTRA_NOTIFICATION_CONTENT); 18 | 19 | if (!isRepeated) { 20 | NotificationUtils.showNotification(context, notificationTitle, content); 21 | } else { 22 | NotificationUtils.showNotification(context, notificationTitle, content); 23 | String eventTitle = intent.getStringExtra(NotificationUtils.EXTRA_EVENT_TITLE); 24 | long eventDate = intent.getLongExtra(NotificationUtils.EXTRA_EVENT_DATE, 0); 25 | String id = intent.getStringExtra(NotificationUtils.EXTRA_EVENT_ID); 26 | 27 | NotificationUtils.buildRepeatedReminder(context, eventDate, eventTitle, id); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_category_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 19 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/manageCategories/smart/SmartCategoriesViewModel.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.manageCategories.smart; 2 | 3 | import android.app.Application; 4 | 5 | import com.gwokhou.deadline.AppPreferences; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.lifecycle.AndroidViewModel; 9 | import androidx.lifecycle.MutableLiveData; 10 | 11 | public class SmartCategoriesViewModel extends AndroidViewModel { 12 | 13 | public MutableLiveData showAllEventsCategory = new MutableLiveData<>(); 14 | public MutableLiveData showTodayEventsCategory = new MutableLiveData<>(); 15 | public MutableLiveData showNext7DaysEventsCategory = new MutableLiveData<>(); 16 | public MutableLiveData showCompletedEventsCategory = new MutableLiveData<>(); 17 | 18 | public SmartCategoriesViewModel(@NonNull Application application) { 19 | super(application); 20 | initSwitch(application); 21 | } 22 | 23 | private void initSwitch(Application application) { 24 | showAllEventsCategory.setValue(AppPreferences.isShowAllEventsCategory(application)); 25 | showTodayEventsCategory.setValue(AppPreferences.isShowTodayEventsCategory(application)); 26 | showNext7DaysEventsCategory.setValue(AppPreferences.isShowNext7DaysEventsCategory(application)); 27 | showCompletedEventsCategory.setValue(AppPreferences.isShowCompletedEventsCategory(application)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/manage_categories_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 21 | 22 | 26 | 27 | 28 | 29 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/DataBindingAdapters.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.util; 2 | 3 | import android.graphics.Typeface; 4 | import android.view.View; 5 | import android.widget.ImageView; 6 | import android.widget.TextView; 7 | 8 | import androidx.databinding.BindingAdapter; 9 | import androidx.navigation.Navigation; 10 | 11 | public class DataBindingAdapters { 12 | 13 | @BindingAdapter("imageId") 14 | public static void setImageRes(ImageView imageView, int resource) { 15 | imageView.setImageResource(resource); 16 | } 17 | 18 | @BindingAdapter("navAction") 19 | public static void setNavAction(final View view, final int actionId) { 20 | if (view != null) { 21 | view.setOnClickListener(new View.OnClickListener() { 22 | @Override 23 | public void onClick(View v) { 24 | Navigation.findNavController(view).navigate(actionId); 25 | } 26 | }); 27 | } 28 | } 29 | 30 | @BindingAdapter("typeface") 31 | public static void setTypeface(TextView textView, String style) { 32 | switch (style) { 33 | case "bold": 34 | textView.setTypeface(null, Typeface.BOLD); 35 | break; 36 | case "italic": 37 | textView.setTypeface(null, Typeface.ITALIC); 38 | break; 39 | default: 40 | textView.setTypeface(null, Typeface.NORMAL); 41 | break; 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 8dp 6 | 176dp 7 | 16dp 8 | 9 | 10 | 36sp 11 | 24sp 12 | 18sp 13 | 16sp 14 | 14sp 15 | 12sp 16 | 10sp 17 | 18 | 19 | 72dp 20 | 40dp 21 | 32dp 22 | 24dp 23 | 16dp 24 | 10dp 25 | 8dp 26 | 6dp 27 | 4dp 28 | 29 | 30 | 24dp 31 | 48dp 32 | 20dp 33 | 176dp 34 | 48dp 35 | 24dp 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/DonateUtils.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.util; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.pm.PackageInfo; 6 | import android.content.pm.PackageManager; 7 | 8 | import java.net.URLEncoder; 9 | 10 | public class DonateUtils { 11 | 12 | private static final String ALIPAY_PACKAGE_NAME = "com.eg.android.AlipayGphone"; 13 | 14 | private static final String ALIPAY_PRE = "alipayqr://platformapi/startapp?saId=10000007&clientVersion=3.7.0.0718&qrcode="; 15 | 16 | private static final String MY_QRCODE = "HTTPS://QR.ALIPAY.COM/FKX03656AL6MG8DA5TAT88?t=1534851150636"; 17 | 18 | 19 | public static boolean startAlipayClient(Activity activity) { 20 | return StartIntentUtils.startIntentUrl(activity, doFormUri(MY_QRCODE)); 21 | } 22 | 23 | private static String doFormUri(String urlCode) { 24 | try { 25 | urlCode = URLEncoder.encode(urlCode, "utf-8"); 26 | } catch (Exception e) { 27 | 28 | } 29 | final String alipayQr = ALIPAY_PRE + urlCode; 30 | return alipayQr + "%3F_s%3Dweb-other&_t=" + System.currentTimeMillis(); 31 | } 32 | 33 | 34 | public static boolean isInstalledAlipayClient(Context context) { 35 | try { 36 | PackageInfo info = context.getPackageManager().getPackageInfo(ALIPAY_PACKAGE_NAME, 0); 37 | return info != null; 38 | } catch (PackageManager.NameNotFoundException e) { 39 | e.printStackTrace(); 40 | return false; 41 | } 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deadline 2 | ![icon](https://github.com/Gwokhov/Deadline/blob/master/pic/ic.png) 3 | 4 | A simple TODO with countdown timer, and also a experimental application with Android Jetpack. 5 | 6 | 一款简洁的结合倒计时钟特性的Todo工具,并且是一个使用Android Jetpack的实验性应用。 7 | 8 | ## Download/下载: 9 | [Coolapk/酷安](https://www.coolapk.com/apk/211123) 10 | 11 | ## Features: 12 | - Support for classifying events. 13 | - 4x2 sorting options. 14 | - Two event modes (normal/durable events). 15 | - 4 status (onging/gone/wait/done), countdown and progress help you to figure out the status of current events. 16 | - Simple UI. 17 | - Quick View card can give an simple data to help you understand the events of the day quicky. 18 | 19 | ## 特性: 20 | - 支持对事件进行分类。 21 | - 提供4x2种排序方法。 22 | - 提供两种事件模式(普通/持续事件)。 23 | - 4种时间状态(进行/过去/等待/完成),倒计时及进度显示,让你更加清晰地了解当前事件状态。 24 | - 简约的交互界面。 25 | - 概览卡片能让你迅速了解当日事项及全部事件状态。 26 | 27 | ## Preview/预览: 28 | ![preview_1](https://github.com/Gwokhov/Deadline/blob/master/pic/preview_1.jpg) 29 | ![preview_2](https://github.com/Gwokhov/Deadline/blob/master/pic/preview_2.jpg) 30 | 31 | ## Android Jetpack Libraries 32 | - Data Binding - Declaratively bind observable data to UI elements. 33 | - Lifecycles - Create a UI that automatically responds to lifecycle events. 34 | - LiveData - Build data objects that notify views when the underlying database changes. 35 | - Navigation - Handle everything needed for in-app navigation. 36 | - Room - Access your app's SQLite database with in-app objects and compile-time checks. 37 | - ViewModel - Store UI-related data that isn't destroyed on app rotations. Easily schedule asynchronous tasks for optimal execution. 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_category_select.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 21 | 22 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_manage_categories.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 19 | 22 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/introduction_feature_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 23 | 24 | 31 | 32 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/SnackbarMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.gwokhou.deadline; 18 | 19 | 20 | import androidx.annotation.Nullable; 21 | import androidx.annotation.StringRes; 22 | import androidx.lifecycle.LifecycleOwner; 23 | import androidx.lifecycle.Observer; 24 | 25 | /** 26 | * A SingleLiveEvent used for Snackbar messages. Like a {@link SingleLiveEvent} but also prevents 27 | * null messages and uses a custom observer. 28 | *

29 | * Note that only one observer is going to be notified of changes. 30 | */ 31 | public class SnackbarMessage extends SingleLiveEvent { 32 | 33 | public void observe(LifecycleOwner owner, final SnackbarObserver observer) { 34 | super.observe(owner, new Observer() { 35 | @Override 36 | public void onChanged(@Nullable Integer t) { 37 | if (t == null) { 38 | return; 39 | } 40 | observer.onNewMessage(t); 41 | } 42 | }); 43 | } 44 | 45 | public interface SnackbarObserver { 46 | /** 47 | * Called when there is a new message to be shown. 48 | * 49 | * @param snackbarMessageResourceId The new message, non-null. 50 | */ 51 | void onNewMessage(@StringRes int snackbarMessageResourceId); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/SortUtils.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.util; 2 | 3 | import com.gwokhou.deadline.data.Event; 4 | 5 | import java.util.Collections; 6 | import java.util.Comparator; 7 | import java.util.List; 8 | 9 | public class SortUtils { 10 | 11 | public static List sortByPriority(List list, boolean isAsc) { 12 | final int asc = isAsc ? 1 : -1; 13 | Collections.sort(list, new Comparator() { 14 | @Override 15 | public int compare(Event t1, Event t2) { 16 | return Integer.compare(t2.getPriority(), t1.getPriority()) * asc; 17 | } 18 | }); 19 | return list; 20 | } 21 | 22 | public static List sortByDueDate(List list, boolean isAsc) { 23 | final int asc = isAsc ? -1 : 1; 24 | Collections.sort(list, new Comparator() { 25 | @Override 26 | public int compare(Event t1, Event t2) { 27 | return Long.compare(t2.getEndDate(), t1.getEndDate()) * asc; 28 | } 29 | }); 30 | return list; 31 | } 32 | 33 | public static List sortByAlpha(List list, boolean isAsc) { 34 | final int asc = isAsc ? 1 : -1; 35 | Collections.sort(list, new Comparator() { 36 | @Override 37 | public int compare(Event t1, Event t2) { 38 | return t1.getTitle().compareToIgnoreCase(t2.getTitle()) * asc; 39 | } 40 | }); 41 | return list; 42 | } 43 | 44 | public static List sortByCreationDate(List list, boolean isAsc) { 45 | final int asc = isAsc ? -1 : 1; 46 | Collections.sort(list, new Comparator() { 47 | @Override 48 | public int compare(Event t1, Event t2) { 49 | return Long.compare(t2.getCreationDate(), t1.getCreationDate()) * asc; 50 | } 51 | }); 52 | return list; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #e9faf9 4 | #E0F2F1 5 | #B2DFDB 6 | #80CBC4 7 | #4DB6AC 8 | #00897B 9 | #00796b 10 | #00695C 11 | 12 | #E57373 13 | #EF5350 14 | #F44336 15 | #D32F2F 16 | #C62828 17 | #B71C1C 18 | 19 | #FFF9C4 20 | #FFF59D 21 | #FFF176 22 | #FFEE58 23 | #FFEB3B 24 | #FDD835 25 | #FBC02D 26 | #F9A825 27 | 28 | 29 | #000000 30 | #de000000 31 | #8a000000 32 | #61000000 33 | #46000000 34 | #20000000 35 | #14000000 36 | 37 | #ffffff 38 | #dcffffff 39 | #b2ffffff 40 | #7fffffff 41 | #50ffffff 42 | #0affffff 43 | 44 | #e0e0e0 45 | #f7f7f7 46 | #fcfcfc 47 | 48 | #00FFFFFF 49 | 50 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_introduction.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 25 | 26 | 34 | 35 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion "28.0.3" 6 | defaultConfig { 7 | applicationId "com.gwokhou.deadline" 8 | minSdkVersion 21 9 | targetSdkVersion 28 10 | versionCode 6 11 | versionName "1.0-beta06" 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | dataBinding { 22 | enabled = true 23 | } 24 | } 25 | 26 | dependencies { 27 | def room_version = '2.0.0' 28 | def lifecycle_version = "2.0.0" 29 | def nav_version = "1.0.0" 30 | def material_version = "1.0.0" 31 | 32 | implementation fileTree(dir: 'libs', include: ['*.jar']) 33 | implementation 'androidx.appcompat:appcompat:1.0.2' 34 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 35 | testImplementation 'junit:junit:4.12' 36 | androidTestImplementation 'androidx.test:runner:1.2.0' 37 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 38 | 39 | // LiveData + ViewModel 40 | implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" 41 | 42 | // Navigation 43 | implementation "android.arch.navigation:navigation-fragment:$nav_version" 44 | implementation "android.arch.navigation:navigation-ui:$nav_version" 45 | 46 | // Room 47 | implementation "androidx.room:room-runtime:$room_version" 48 | annotationProcessor "androidx.room:room-compiler:$room_version" 49 | 50 | // Material 51 | implementation "com.google.android.material:material:$material_version" 52 | 53 | implementation 'com.github.vipulasri:timelineview:1.0.6' 54 | implementation 'com.github.iwgang:countdownview:2.1.6' 55 | implementation 'com.pacioianu.david:ink-page-indicator:1.3.0' 56 | implementation 'devlight.io:arcprogressstackview:1.0.4' 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | import androidx.navigation.Navigation; 5 | 6 | import android.app.NotificationChannel; 7 | import android.app.NotificationManager; 8 | import android.os.Build; 9 | import android.os.Bundle; 10 | 11 | import com.gwokhou.deadline.events.BackPressedHandler; 12 | import com.gwokhou.deadline.events.EventsFragment; 13 | 14 | public class MainActivity extends AppCompatActivity implements BackPressedHandler { 15 | 16 | public static final String EVENT_NOTIFICATION_ID = "EVENT_NOTIFICATION"; 17 | 18 | private EventsFragment mEventsFragment; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.navigation_activity); 24 | 25 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 26 | NotificationChannel channel = new NotificationChannel(EVENT_NOTIFICATION_ID, getString(R.string.event_notification), NotificationManager.IMPORTANCE_HIGH); 27 | NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 28 | manager.createNotificationChannel(channel); 29 | } 30 | 31 | setupIntroPage(); 32 | 33 | } 34 | 35 | @Override 36 | public boolean onSupportNavigateUp() { 37 | return Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp(); 38 | } 39 | 40 | private void setupIntroPage() { 41 | if (AppPreferences.isFirstBoot(this)) { 42 | Navigation.findNavController(this, R.id.nav_host_fragment).navigate(R.id.action_events_to_intro); 43 | } 44 | } 45 | 46 | @Override 47 | public void onBackPressed() { 48 | if (mEventsFragment == null || !mEventsFragment.onBackPressed() || !mEventsFragment.isVisible()) { 49 | super.onBackPressed(); 50 | } 51 | } 52 | 53 | @Override 54 | public void setSelectedFragment(EventsFragment fragment) { 55 | mEventsFragment = fragment; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/fragments/TypeTipsDialogFragment.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.fragments; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.os.Bundle; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | 11 | import com.gwokhou.deadline.R; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.annotation.Nullable; 15 | import androidx.appcompat.app.AlertDialog; 16 | import androidx.fragment.app.DialogFragment; 17 | 18 | public class TypeTipsDialogFragment extends DialogFragment { 19 | 20 | public static final String EXTRA_HAS_OPEN_TYPE_TIPS = "EXTRA_HAS_OPEN_TYPE_TIPS"; 21 | 22 | public static TypeTipsDialogFragment newInstance() { 23 | return new TypeTipsDialogFragment(); 24 | } 25 | 26 | @NonNull 27 | @Override 28 | public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { 29 | 30 | View view = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_about_durable_event, null); 31 | 32 | AlertDialog dialog = new AlertDialog.Builder(getActivity()) 33 | .setTitle(R.string.about_durable_event) 34 | .setView(view) 35 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 36 | @Override 37 | public void onClick(DialogInterface dialogInterface, int i) { 38 | sendResult(Activity.RESULT_OK, true); 39 | dismiss(); 40 | } 41 | }) 42 | .create(); 43 | dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation; 44 | return dialog; 45 | } 46 | 47 | private void sendResult(int resultCode, boolean hasOpen) { 48 | if (getTargetFragment() == null) { 49 | return; 50 | } 51 | Intent intent = new Intent(); 52 | intent.putExtra(EXTRA_HAS_OPEN_TYPE_TIPS, hasOpen); 53 | getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, intent); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/res/layout/introduction_welcome.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 20 | 21 | 27 | 28 | 29 | 30 | 36 | 37 | 44 | 45 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/sort/SortBottomSheetFragment.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.sort; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment; 9 | import com.gwokhou.deadline.R; 10 | import com.gwokhou.deadline.databinding.SortBottomSheetBinding; 11 | import com.gwokhou.deadline.events.EventsViewModel; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.annotation.Nullable; 15 | import androidx.lifecycle.ViewModelProviders; 16 | 17 | public class SortBottomSheetFragment extends BottomSheetDialogFragment { 18 | 19 | private EventsViewModel mViewModel; 20 | 21 | public static SortBottomSheetFragment newInstance() { 22 | 23 | return new SortBottomSheetFragment(); 24 | } 25 | 26 | @Nullable 27 | @Override 28 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 29 | return inflater.inflate(R.layout.sort_bottom_sheet, container, false); 30 | } 31 | 32 | @Override 33 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 34 | super.onViewCreated(view, savedInstanceState); 35 | 36 | SortBottomSheetBinding binding = SortBottomSheetBinding.bind(view); 37 | mViewModel = ViewModelProviders.of(getActivity()).get(EventsViewModel.class); 38 | binding.setViewmodel(mViewModel); 39 | 40 | SortItemActionListener listener = getSortItemActionListener(); 41 | 42 | binding.setListener(listener); 43 | } 44 | 45 | private SortItemActionListener getSortItemActionListener() { 46 | return new SortItemActionListener() { 47 | @Override 48 | public void onItemClicked(int type) { 49 | mViewModel.mListener.onSortUpdate(type); 50 | getDialog().dismiss(); 51 | } 52 | 53 | @Override 54 | public void onSwitchedSortOrder(boolean isAsc) { 55 | mViewModel.mListener.onIsAscUpdate(isAsc); 56 | getDialog().dismiss(); 57 | } 58 | }; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/FilterUtils.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.util; 2 | 3 | import com.gwokhou.deadline.data.Event; 4 | import com.gwokhou.deadline.dataType.StateType; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class FilterUtils { 10 | 11 | public static List filterTodayTasks(List events) { 12 | List mEvent = new ArrayList<>(); 13 | for (Event event : events) { 14 | if (event.getEndDate() >= DateTimeUtils.getTodayStart() && event.getEndDate() <= DateTimeUtils.getTodayEnd()) { 15 | mEvent.add(event); 16 | } 17 | } 18 | return mEvent; 19 | } 20 | 21 | public static List filterNext7DaysTasks(List events) { 22 | List mEvent = new ArrayList<>(); 23 | for (Event event : events) { 24 | if (event.getEndDate() >= DateTimeUtils.getTodayStart() && event.getEndDate() <= DateTimeUtils.getNext7DaysEnd()) { 25 | mEvent.add(event); 26 | } 27 | } 28 | return mEvent; 29 | } 30 | 31 | public static List filterCompletedEvents(List events) { 32 | List mEvent = new ArrayList<>(); 33 | for (Event event : events) { 34 | if (event.getState() == StateType.COMPLETED) { 35 | mEvent.add(event); 36 | } 37 | } 38 | return mEvent; 39 | } 40 | 41 | public static List filterCategoryEvents(List events, String category) { 42 | List mEvent = new ArrayList<>(); 43 | for (Event event : events) { 44 | if (event.getCategory().equals(category)) { 45 | mEvent.add(event); 46 | } 47 | } 48 | return mEvent; 49 | } 50 | 51 | public static List filterUncompletedEvents(List events) { 52 | List mEvent = new ArrayList<>(); 53 | for (Event event : events) { 54 | if (event.getState() != StateType.COMPLETED) { 55 | mEvent.add(event); 56 | } 57 | } 58 | return mEvent; 59 | } 60 | 61 | public static List cloneEvents(List events) { 62 | return new ArrayList<>(events); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/SystemUIUtils.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.util; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Color; 6 | import android.os.Build; 7 | import android.view.View; 8 | import android.view.Window; 9 | import android.view.WindowManager; 10 | import android.view.inputmethod.InputMethodManager; 11 | 12 | 13 | import com.gwokhou.deadline.R; 14 | 15 | import androidx.appcompat.app.ActionBar; 16 | import androidx.appcompat.app.AppCompatActivity; 17 | import androidx.appcompat.widget.Toolbar; 18 | 19 | public class SystemUIUtils { 20 | 21 | public static void setupActionBar(Activity activity, boolean isLightBar, int bgColorRes, int bgColorRes2, int titleRes, Toolbar toolbar) { 22 | Window window = activity.getWindow(); 23 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 24 | window.setStatusBarColor(activity.getResources().getColor(bgColorRes2)); 25 | if (!isLightBar) { 26 | toolbar.setTitleTextColor(activity.getResources().getColor(R.color.white)); 27 | } 28 | } else { 29 | window.setStatusBarColor(activity.getResources().getColor(bgColorRes, null)); 30 | if (isLightBar) { 31 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); 32 | } else { 33 | toolbar.setTitleTextColor(activity.getResources().getColor(R.color.white)); 34 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); 35 | } 36 | } 37 | 38 | toolbar.setTitle(activity.getString(titleRes)); 39 | ((AppCompatActivity) activity).setSupportActionBar(toolbar); 40 | ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar(); 41 | if (actionBar != null) { 42 | actionBar.setDisplayShowHomeEnabled(true); 43 | } 44 | } 45 | 46 | public static void hideKeyBoard(Activity activity) { 47 | if ((activity.getCurrentFocus() != null) && (activity.getCurrentFocus().getWindowToken() != null)) { 48 | ((InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE)). 49 | hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/AppExecutors.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.gwokhou.deadline.util; 18 | 19 | import android.os.Handler; 20 | import android.os.Looper; 21 | 22 | import java.util.concurrent.Executor; 23 | import java.util.concurrent.Executors; 24 | 25 | import androidx.annotation.NonNull; 26 | import androidx.annotation.VisibleForTesting; 27 | 28 | /** 29 | * Global executor pools for the whole application. 30 | *

31 | * Grouping tasks like this avoids the effects of task starvation (e.g. disk reads don't wait behind 32 | * webservice requests). 33 | */ 34 | public class AppExecutors { 35 | 36 | private static final int THREAD_COUNT = 3; 37 | 38 | private final Executor diskIO; 39 | 40 | private final Executor networkIO; 41 | 42 | private final Executor mainThread; 43 | 44 | @VisibleForTesting 45 | AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) { 46 | this.diskIO = diskIO; 47 | this.networkIO = networkIO; 48 | this.mainThread = mainThread; 49 | } 50 | 51 | public AppExecutors() { 52 | this(new DiskIOThreadExecutor(), Executors.newFixedThreadPool(THREAD_COUNT), 53 | new MainThreadExecutor()); 54 | } 55 | 56 | public Executor diskIO() { 57 | return diskIO; 58 | } 59 | 60 | public Executor networkIO() { 61 | return networkIO; 62 | } 63 | 64 | public Executor mainThread() { 65 | return mainThread; 66 | } 67 | 68 | private static class MainThreadExecutor implements Executor { 69 | private Handler mainThreadHandler = new Handler(Looper.getMainLooper()); 70 | 71 | @Override 72 | public void execute(@NonNull Runnable command) { 73 | mainThreadHandler.post(command); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/categorySelector/CategorySelectDialogViewModel.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.categorySelector; 2 | 3 | import android.app.Application; 4 | 5 | import com.gwokhou.deadline.R; 6 | import com.gwokhou.deadline.data.Category; 7 | import com.gwokhou.deadline.data.CategoryDataSource; 8 | import com.gwokhou.deadline.data.DeadlineRepository; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import androidx.lifecycle.AndroidViewModel; 14 | 15 | public class CategorySelectDialogViewModel extends AndroidViewModel { 16 | 17 | private DeadlineRepository mRepository; 18 | 19 | private CategoriesLoadedListener mLoadedListener; 20 | 21 | private List mCategories = new ArrayList<>(0); 22 | 23 | private ArrayList mCategoriesName = new ArrayList<>(0); 24 | 25 | String currentSelected = getApplication().getString(R.string.inbox); 26 | 27 | public CategorySelectDialogViewModel(Application application) { 28 | super(application); 29 | mRepository = DeadlineRepository.getInstance(application); 30 | } 31 | 32 | void updateSelected(String category) { 33 | currentSelected = category; 34 | } 35 | 36 | void updateCategories() { 37 | mRepository.getAllCategories(new CategoryDataSource.LoadCategoriesCallback() { 38 | @Override 39 | public void onCategoriesLoaded(List categories) { 40 | mCategories.clear(); 41 | mCategories.addAll(categories); 42 | 43 | mCategoriesName.clear(); 44 | for (Category category : mCategories) { 45 | mCategoriesName.add(category.getName()); 46 | } 47 | } 48 | 49 | @Override 50 | public void onDataNotAvailable() { 51 | } 52 | }); 53 | if (mLoadedListener != null) { 54 | mCategories.add(0, new Category(getApplication().getString(R.string.inbox), "inbox")); 55 | mLoadedListener.onLoadedFinished(mCategories); 56 | } 57 | } 58 | 59 | ArrayList getCategoriesNames() { 60 | return mCategoriesName; 61 | } 62 | 63 | void addCategory(String categoryName) { 64 | mRepository.saveCategory(new Category(categoryName)); 65 | updateCategories(); 66 | } 67 | 68 | void setLoadedListener(CategoriesLoadedListener loadedListener) { 69 | mLoadedListener = loadedListener; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/fragments/SimpleAlertDialogFragment.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.fragments; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.app.Dialog; 6 | import android.content.DialogInterface; 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.annotation.Nullable; 12 | import androidx.fragment.app.DialogFragment; 13 | 14 | public class SimpleAlertDialogFragment extends DialogFragment { 15 | 16 | public static final String EXTRA_IS_CONFIRM = "EXTRA_IS_CONFIRM"; 17 | 18 | private static final String ARG_TITLE = "TITLE"; 19 | 20 | private static final String ARG_CONTENT = "CONTENT"; 21 | 22 | public static SimpleAlertDialogFragment newInstance(int titleRes, int contentRes) { 23 | Bundle args = new Bundle(); 24 | args.putInt(ARG_TITLE, titleRes); 25 | args.putInt(ARG_CONTENT, contentRes); 26 | SimpleAlertDialogFragment fragment = new SimpleAlertDialogFragment(); 27 | fragment.setArguments(args); 28 | return fragment; 29 | } 30 | 31 | @NonNull 32 | @Override 33 | public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { 34 | int argTitle = getArguments().getInt(ARG_TITLE); 35 | int argContent = getArguments().getInt(ARG_CONTENT); 36 | 37 | return new AlertDialog.Builder(getContext()) 38 | .setTitle(argTitle) 39 | .setMessage(argContent) 40 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 41 | @Override 42 | public void onClick(DialogInterface dialog, int which) { 43 | sendResult(Activity.RESULT_OK, true); 44 | } 45 | }) 46 | .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { 47 | @Override 48 | public void onClick(DialogInterface dialog, int which) { 49 | sendResult(Activity.RESULT_OK, false); 50 | dismiss(); 51 | } 52 | }) 53 | .create(); 54 | } 55 | 56 | private void sendResult(int resultCode, boolean isConfirm) { 57 | if (getTargetFragment() == null) { 58 | return; 59 | } 60 | Intent intent = new Intent(); 61 | intent.putExtra(EXTRA_IS_CONFIRM, isConfirm); 62 | getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, intent); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/events/item/EventTouchHelperCallback.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.events.item; 2 | 3 | import android.graphics.Canvas; 4 | import android.view.ViewGroup; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.recyclerview.widget.ItemTouchHelper; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | public class EventTouchHelperCallback extends ItemTouchHelper.Callback { 11 | 12 | private EventTouchHelperListener mEventTouchHelperListener; 13 | 14 | public EventTouchHelperCallback(EventTouchHelperListener listener) { 15 | mEventTouchHelperListener = listener; 16 | } 17 | 18 | @Override 19 | public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { 20 | int swipeFlags = ItemTouchHelper.START; 21 | return makeMovementFlags(0, swipeFlags); 22 | } 23 | 24 | @Override 25 | public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { 26 | // mEventTouchHelperListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); 27 | return false; 28 | } 29 | 30 | @Override 31 | public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { 32 | mEventTouchHelperListener.onItemSwipeToStart(viewHolder.getAdapterPosition()); 33 | } 34 | 35 | @Override 36 | public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { 37 | super.clearView(recyclerView, viewHolder); 38 | viewHolder.itemView.setScrollX(0); 39 | } 40 | 41 | @Override 42 | public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { 43 | if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { 44 | if (Math.abs(dX) <= getSlideLimitation(viewHolder)) { 45 | viewHolder.itemView.scrollTo(-(int) dX, 0); 46 | } 47 | 48 | } else { 49 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 50 | } 51 | } 52 | 53 | public int getSlideLimitation(RecyclerView.ViewHolder viewHolder) { 54 | ViewGroup viewGroup = (ViewGroup) viewHolder.itemView; 55 | return viewGroup.getChildAt(3).getLayoutParams().width; 56 | } 57 | 58 | @Override 59 | public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { 60 | return 0.3f; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/manageCategories/custom/CustomCategoriesAdapter.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.manageCategories.custom; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import com.gwokhou.deadline.R; 10 | import com.gwokhou.deadline.data.Category; 11 | 12 | import java.util.List; 13 | 14 | import androidx.annotation.NonNull; 15 | import androidx.recyclerview.widget.RecyclerView; 16 | 17 | public class CustomCategoriesAdapter extends RecyclerView.Adapter { 18 | 19 | private List mCategoryList; 20 | 21 | private CustomCategoryItemActionListener mCustomCategoryItemActionListener; 22 | 23 | private LayoutInflater mInflater; 24 | 25 | 26 | class ViewHolder extends RecyclerView.ViewHolder { 27 | 28 | TextView categoryName; 29 | 30 | ViewHolder(View view) { 31 | super(view); 32 | categoryName = view.findViewById(R.id.custom_category_name); 33 | } 34 | } 35 | 36 | public CustomCategoriesAdapter(Context context) { 37 | mInflater = LayoutInflater.from(context); 38 | } 39 | 40 | @NonNull 41 | @Override 42 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 43 | View itemView = mInflater.inflate(R.layout.item_custom_category, parent, false); 44 | return new ViewHolder(itemView); 45 | } 46 | 47 | @Override 48 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 49 | if (mCategoryList != null) { 50 | final Category current = mCategoryList.get(position); 51 | holder.categoryName.setText(current.getName()); 52 | 53 | if (mCustomCategoryItemActionListener != null) { 54 | holder.itemView.setOnClickListener(new View.OnClickListener() { 55 | @Override 56 | public void onClick(View v) { 57 | mCustomCategoryItemActionListener.onItemClicked(current.getId()); 58 | } 59 | }); 60 | } 61 | 62 | } 63 | } 64 | 65 | @Override 66 | public int getItemCount() { 67 | if (mCategoryList != null) { 68 | return mCategoryList.size(); 69 | } else { 70 | return 0; 71 | } 72 | } 73 | 74 | public void setCategoryList(List categories) { 75 | mCategoryList = categories; 76 | notifyDataSetChanged(); 77 | } 78 | 79 | public void setCustomCategoryItemActionListener(CustomCategoryItemActionListener listener) { 80 | mCustomCategoryItemActionListener = listener; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/SingleLiveEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.gwokhou.deadline; 18 | 19 | 20 | import android.util.Log; 21 | 22 | import java.util.concurrent.atomic.AtomicBoolean; 23 | 24 | import androidx.annotation.MainThread; 25 | import androidx.annotation.NonNull; 26 | import androidx.annotation.Nullable; 27 | import androidx.lifecycle.LifecycleOwner; 28 | import androidx.lifecycle.MutableLiveData; 29 | import androidx.lifecycle.Observer; 30 | 31 | /** 32 | * A lifecycle-aware observable that sends only new updates after subscription, used for events like 33 | * navigation and Snackbar messages. 34 | *

35 | * This avoids a common problem with events: on configuration change (like rotation) an update 36 | * can be emitted if the observer is active. This LiveData only calls the observable if there's an 37 | * explicit call to setValue() or call(). 38 | *

39 | * Note that only one observer is going to be notified of changes. 40 | */ 41 | public class SingleLiveEvent extends MutableLiveData { 42 | 43 | private static final String TAG = "SingleLiveEvent"; 44 | 45 | private final AtomicBoolean mPending = new AtomicBoolean(false); 46 | 47 | 48 | @MainThread 49 | @Override 50 | public void observe(@NonNull LifecycleOwner owner, @NonNull final Observer observer) { 51 | if (hasActiveObservers()) { 52 | Log.w(TAG, "Multiple observers registered but only one will be notified of changes."); 53 | } 54 | 55 | // Observe the internal MutableLiveData 56 | super.observe(owner, new Observer() { 57 | @Override 58 | public void onChanged(@Nullable T t) { 59 | if (mPending.compareAndSet(true, false)) { 60 | observer.onChanged(t); 61 | } 62 | } 63 | }); 64 | 65 | } 66 | 67 | @MainThread 68 | public void setValue(@Nullable T t) { 69 | mPending.set(true); 70 | super.setValue(t); 71 | } 72 | 73 | /** 74 | * Used for cases where T is Void, to make calls cleaner. 75 | */ 76 | @MainThread 77 | public void call() { 78 | setValue(null); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_licenses.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 14 | 15 | 23 | 24 | 29 | 30 | 36 | 37 | 42 | 43 | 49 | 50 | 55 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/manageCategories/ManageCategoriesFragment.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.manageCategories; 2 | 3 | import androidx.appcompat.widget.Toolbar; 4 | 5 | import android.os.Bundle; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | import androidx.fragment.app.Fragment; 10 | import androidx.viewpager.widget.ViewPager; 11 | 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | 16 | import com.google.android.material.tabs.TabLayout; 17 | import com.gwokhou.deadline.R; 18 | import com.gwokhou.deadline.manageCategories.custom.CustomCategoriesFragment; 19 | import com.gwokhou.deadline.manageCategories.smart.SmartCategoriesFragment; 20 | import com.gwokhou.deadline.util.SystemUIUtils; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public class ManageCategoriesFragment extends Fragment { 26 | 27 | public static ManageCategoriesFragment newInstance() { 28 | return new ManageCategoriesFragment(); 29 | } 30 | 31 | @Override 32 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, 33 | @Nullable Bundle savedInstanceState) { 34 | setHasOptionsMenu(true); 35 | return inflater.inflate(R.layout.manage_categories_fragment, container, false); 36 | } 37 | 38 | @Override 39 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 40 | super.onViewCreated(view, savedInstanceState); 41 | setupSystemUI(); 42 | setupTabLayout(); 43 | } 44 | 45 | private void setupSystemUI() { 46 | Toolbar toolbar = getView().findViewById(R.id.manage_categories_toolbar); 47 | SystemUIUtils.setupActionBar(getActivity(), true, R.color.white, R.color.teal_200, R.string.manage_categories, toolbar); 48 | } 49 | 50 | private void setupTabLayout() { 51 | TabLayout tabLayout = getView().findViewById(R.id.manage_categories_tab); 52 | ViewPager viewPager = getView().findViewById(R.id.manage_categories_view_pager); 53 | 54 | String[] tabTitles = {getString(R.string.custom_categories), getString(R.string.smart_categories)}; 55 | 56 | List fragments = new ArrayList<>(); 57 | fragments.add(CustomCategoriesFragment.newInstance()); 58 | fragments.add(SmartCategoriesFragment.newInstance()); 59 | 60 | ManageCategoriesPagerAdapter pagerAdapter = new ManageCategoriesPagerAdapter(getChildFragmentManager(), fragments, tabTitles); 61 | viewPager.setAdapter(pagerAdapter); 62 | 63 | tabLayout.setupWithViewPager(viewPager); 64 | 65 | tabLayout.getTabAt(0).setText(R.string.custom_categories).setIcon(R.drawable.ic_category); 66 | tabLayout.getTabAt(1).setText(R.string.smart_categories).setIcon(R.drawable.ic_next_7_days); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/manageCategories/custom/CustomCategoriesViewModel.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.manageCategories.custom; 2 | 3 | import android.app.Application; 4 | 5 | import com.gwokhou.deadline.data.Category; 6 | import com.gwokhou.deadline.data.CategoryDataSource; 7 | import com.gwokhou.deadline.data.DeadlineRepository; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.databinding.ObservableArrayList; 14 | import androidx.databinding.ObservableList; 15 | import androidx.lifecycle.AndroidViewModel; 16 | 17 | public class CustomCategoriesViewModel extends AndroidViewModel { 18 | 19 | public ObservableList items = new ObservableArrayList<>(); 20 | 21 | private Category cacheCategory; 22 | 23 | public boolean isOpenNewCategory = false; 24 | 25 | private DeadlineRepository mRepository; 26 | 27 | private ArrayList mCategoriesName = new ArrayList<>(0); 28 | 29 | public CustomCategoriesViewModel(@NonNull Application application) { 30 | super(application); 31 | mRepository = DeadlineRepository.getInstance(application); 32 | initCategories(); 33 | } 34 | 35 | private void initCategories() { 36 | mRepository.getAllCategories(new CategoryDataSource.LoadCategoriesCallback() { 37 | @Override 38 | public void onCategoriesLoaded(List categories) { 39 | items.clear(); 40 | items.addAll(categories); 41 | 42 | mCategoriesName.clear(); 43 | for (Category category : categories) { 44 | mCategoriesName.add(category.getName()); 45 | } 46 | } 47 | 48 | @Override 49 | public void onDataNotAvailable() { } 50 | }); 51 | } 52 | 53 | public ArrayList getCategoriesName() { 54 | return mCategoriesName; 55 | } 56 | 57 | private void getCategory(String id) { 58 | mRepository.getCategory(id, new CategoryDataSource.GetCategoryCallback() { 59 | @Override 60 | public void onCategoryLoaded(Category category) { 61 | cacheCategory = category; 62 | } 63 | 64 | @Override 65 | public void onDataNotAvailable() { } 66 | }); 67 | } 68 | 69 | public String getCategoryName(String id) { 70 | getCategory(id); 71 | return cacheCategory.getName(); 72 | } 73 | 74 | public void addCategory(String categoryName) { 75 | mRepository.saveCategory(new Category(categoryName)); 76 | initCategories(); 77 | } 78 | 79 | public void updateCategory(String categoryName) { 80 | mRepository.saveCategory(new Category(categoryName, cacheCategory.getId())); 81 | initCategories(); 82 | } 83 | 84 | public void deleteCategory() { 85 | mRepository.deleteCategory(cacheCategory.getId()); 86 | initCategories(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/settings/SettingsViewModel.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.settings; 2 | 3 | import android.app.Application; 4 | 5 | import com.gwokhou.deadline.AppPreferences; 6 | import com.gwokhou.deadline.util.ResourceValueUtils; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.arch.core.util.Function; 10 | import androidx.lifecycle.AndroidViewModel; 11 | import androidx.lifecycle.LiveData; 12 | import androidx.lifecycle.MutableLiveData; 13 | import androidx.lifecycle.Transformations; 14 | 15 | public class SettingsViewModel extends AndroidViewModel { 16 | 17 | private Application mApplication; 18 | 19 | public MutableLiveData isDurableModeDefault = new MutableLiveData<>(); 20 | 21 | public MutableLiveData enableQuickView = new MutableLiveData<>(); 22 | 23 | public MutableLiveData isMondayWeekStart = new MutableLiveData<>(); 24 | 25 | public MutableLiveData dailyRemindTime = new MutableLiveData<>(); 26 | 27 | public MutableLiveData quickViewBehavior = new MutableLiveData<>(); 28 | public LiveData quickViewBehDesc = Transformations.map(quickViewBehavior, new Function() { 29 | @Override 30 | public String apply(Integer behavior) { 31 | return getQuickViewBehaviorDesc(behavior); 32 | } 33 | }); 34 | 35 | public SettingsViewModel(@NonNull Application application) { 36 | super(application); 37 | mApplication = getApplication(); 38 | loadData(); 39 | } 40 | 41 | private void loadData() { 42 | isDurableModeDefault.setValue(AppPreferences.isDurableEvent(mApplication)); 43 | enableQuickView.setValue(AppPreferences.isEnableQuickView(mApplication)); 44 | isMondayWeekStart.setValue(AppPreferences.isMondayTheFirstDay(mApplication)); 45 | dailyRemindTime.setValue(AppPreferences.getDailyRemindTime(mApplication)); 46 | quickViewBehavior.setValue(AppPreferences.getQuickViewBehavior(mApplication)); 47 | } 48 | 49 | void updateStartOfWeek(boolean isMonday) { 50 | AppPreferences.setIsMondayTheFirstDay(mApplication, isMonday); 51 | isMondayWeekStart.setValue(isMonday); 52 | } 53 | 54 | void updateDailyRemindTime(long time) { 55 | AppPreferences.setDailyRemindTime(mApplication, time); 56 | dailyRemindTime.setValue(time); 57 | } 58 | 59 | void updateDefaultEventMode(boolean isDurableMode) { 60 | AppPreferences.setIsDurableEvent(mApplication, isDurableMode); 61 | } 62 | 63 | void updateEnableQuickView(boolean isEnable) { 64 | AppPreferences.setEnableQuickView(mApplication, isEnable); 65 | } 66 | 67 | void updateQuickViewBehavior(int behavior) { 68 | AppPreferences.setQuickViewBehavior(mApplication, behavior); 69 | quickViewBehavior.setValue(behavior); 70 | } 71 | 72 | private String getQuickViewBehaviorDesc(int behavior) { 73 | 74 | int res = ResourceValueUtils.getQuickViewBehDesc(behavior); 75 | 76 | return mApplication.getString(res); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_about_durable_event.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 21 | 22 | 30 | 31 | 36 | 37 | 42 | 43 | 52 | 53 | 61 | 62 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/manageCategories/smart/SmartCategoriesFragment.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.manageCategories.smart; 2 | 3 | import androidx.lifecycle.Observer; 4 | import androidx.lifecycle.ViewModelProviders; 5 | 6 | import android.os.Bundle; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.Nullable; 10 | import androidx.fragment.app.Fragment; 11 | 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | 16 | import com.gwokhou.deadline.AppPreferences; 17 | import com.gwokhou.deadline.R; 18 | import com.gwokhou.deadline.databinding.FragmentSmartCategoriesBinding; 19 | import com.gwokhou.deadline.util.UpdateSelectedCategoryPreferences; 20 | 21 | public class SmartCategoriesFragment extends Fragment{ 22 | 23 | private SmartCategoriesViewModel mViewModel; 24 | 25 | public static SmartCategoriesFragment newInstance() { 26 | return new SmartCategoriesFragment(); 27 | } 28 | 29 | @Override 30 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, 31 | @Nullable Bundle savedInstanceState) { 32 | View view = inflater.inflate(R.layout.fragment_smart_categories, container, false); 33 | FragmentSmartCategoriesBinding binding = FragmentSmartCategoriesBinding.bind(view); 34 | mViewModel = ViewModelProviders.of(this).get(SmartCategoriesViewModel.class); 35 | binding.setViewModel(mViewModel); 36 | 37 | return view; 38 | } 39 | 40 | @Override 41 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 42 | super.onActivityCreated(savedInstanceState); 43 | 44 | setupSwitch(); 45 | } 46 | 47 | private void setupSwitch() { 48 | mViewModel.showAllEventsCategory.observe(this, new Observer() { 49 | @Override 50 | public void onChanged(Boolean isShow) { 51 | AppPreferences.setIsShowAllEventsCategory(getContext(), isShow); 52 | UpdateSelectedCategoryPreferences.updateAppPreferences(getContext()); 53 | } 54 | }); 55 | 56 | mViewModel.showTodayEventsCategory.observe(this, new Observer() { 57 | @Override 58 | public void onChanged(Boolean isShow) { 59 | AppPreferences.setIsShowTodayEventsCategory(getContext(), isShow); 60 | UpdateSelectedCategoryPreferences.updateAppPreferences(getContext()); 61 | } 62 | }); 63 | 64 | mViewModel.showNext7DaysEventsCategory.observe(this, new Observer() { 65 | @Override 66 | public void onChanged(Boolean isShow) { 67 | AppPreferences.setIsShowNext7DaysEventsCategory(getContext(), isShow); 68 | UpdateSelectedCategoryPreferences.updateAppPreferences(getContext()); 69 | } 70 | }); 71 | 72 | mViewModel.showCompletedEventsCategory.observe(this, new Observer() { 73 | @Override 74 | public void onChanged(Boolean isShow) { 75 | AppPreferences.setIsShowCompletedEventsCategory(getContext(), isShow); 76 | UpdateSelectedCategoryPreferences.updateAppPreferences(getContext()); 77 | } 78 | }); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ils_morning.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/data/Event.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.data; 2 | 3 | 4 | import java.util.UUID; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | import androidx.room.ColumnInfo; 9 | import androidx.room.Entity; 10 | import androidx.room.Ignore; 11 | import androidx.room.PrimaryKey; 12 | 13 | @Entity(tableName = "event_table") 14 | public class Event { 15 | 16 | @PrimaryKey 17 | @NonNull 18 | @ColumnInfo(name = "entry_id") 19 | private String mId; 20 | 21 | @Nullable 22 | @ColumnInfo(name = "title") 23 | private String mTitle; 24 | 25 | @Nullable 26 | @ColumnInfo(name = "note") 27 | private String mNote; 28 | 29 | @ColumnInfo(name = "start_date") 30 | private long mStartDate; 31 | 32 | @ColumnInfo(name = "end_date") 33 | private long mEndDate; 34 | 35 | @ColumnInfo(name = "state") 36 | private int mState; 37 | 38 | @ColumnInfo(name = "durable_event") 39 | private boolean mDurableEvent; 40 | 41 | @ColumnInfo(name = "priority") 42 | private int mPriority; 43 | 44 | @ColumnInfo(name = "reminder") 45 | private int mReminder; 46 | 47 | @ColumnInfo(name = "category") 48 | private String mCategory; 49 | 50 | @ColumnInfo(name = "creation_date") 51 | private long mCreationDate; 52 | 53 | //Use this constructor to create a new active Event. 54 | @Ignore 55 | public Event(@Nullable String title, @Nullable String note, long startDate, long endDate, int state, boolean durableEvent, int priority, int reminder, String category) { 56 | this(title, note, startDate, endDate, state, durableEvent, priority, UUID.randomUUID().toString(), reminder, category, System.currentTimeMillis()); 57 | } 58 | 59 | public Event(@Nullable String title, @Nullable String note, long startDate, long endDate, int state, boolean durableEvent, int priority, String id, int reminder, String category, long creationDate) { 60 | mId = id; 61 | mCreationDate = creationDate; 62 | mTitle = title; 63 | mNote = note; 64 | mStartDate = startDate; 65 | mEndDate = endDate; 66 | mState = state; 67 | mDurableEvent = durableEvent; 68 | mPriority = priority; 69 | mReminder = reminder; 70 | mCategory = category; 71 | } 72 | 73 | @NonNull 74 | public String getId() { 75 | return mId; 76 | } 77 | 78 | public long getCreationDate() { 79 | return mCreationDate; 80 | } 81 | 82 | @Nullable 83 | public String getTitle() { 84 | return mTitle; 85 | } 86 | 87 | @Nullable 88 | public String getNote() { 89 | return mNote; 90 | } 91 | 92 | public long getStartDate() { 93 | return mStartDate; 94 | } 95 | 96 | public long getEndDate() { 97 | return mEndDate; 98 | } 99 | 100 | public int getState() { 101 | return mState; 102 | } 103 | 104 | public boolean isDurableEvent() { 105 | return mDurableEvent; 106 | } 107 | 108 | public int getPriority() { 109 | return mPriority; 110 | } 111 | 112 | public int getReminder() { 113 | return mReminder; 114 | } 115 | 116 | public String getCategory() { 117 | return mCategory; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/reminderSelect/ReminderDialogViewModel.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.reminderSelect; 2 | 3 | import android.app.Application; 4 | 5 | import com.gwokhou.deadline.R; 6 | import com.gwokhou.deadline.dataType.RemindType; 7 | import com.gwokhou.deadline.util.ReminderUtils; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.databinding.ObservableArrayMap; 11 | import androidx.databinding.ObservableField; 12 | import androidx.lifecycle.AndroidViewModel; 13 | 14 | public class ReminderDialogViewModel extends AndroidViewModel { 15 | 16 | public ObservableArrayMap remindSelections = new ObservableArrayMap<>(); 17 | 18 | public ObservableField singleRemindInterval = new ObservableField<>("10"); 19 | 20 | public ObservableField singleRemindUnit = new ObservableField<>(RemindType.SINGLE_MIN); 21 | 22 | public ReminderDialogViewModel(@NonNull Application application) { 23 | super(application); 24 | initSelections(); 25 | } 26 | 27 | private void initSelections() { 28 | remindSelections.put(RemindType.NONE_REMIND, true); 29 | remindSelections.put(RemindType.SINGLE_DUE_DATE, false); 30 | remindSelections.put(RemindType.SINGLE_REMIND, false); 31 | remindSelections.put(RemindType.REPEATED_EVERYDAY, false); 32 | remindSelections.put(RemindType.REPEATED_ALWAYS, false); 33 | } 34 | 35 | public void updateSelections(int type) { 36 | for (int i : remindSelections.keySet()) { 37 | if (i == type) { 38 | remindSelections.put(i, true); 39 | } else { 40 | remindSelections.put(i, false); 41 | } 42 | } 43 | } 44 | 45 | private int getRemindType() { 46 | for (int i : remindSelections.keySet()) { 47 | if (remindSelections.get(i)) { 48 | if (i == RemindType.SINGLE_REMIND) { 49 | return singleRemindUnit.get(); 50 | } else { 51 | return i; 52 | } 53 | } 54 | } 55 | return RemindType.NONE_REMIND; 56 | } 57 | 58 | public void loadData(int typeData) { 59 | int type = ReminderUtils.getRemindType(typeData); 60 | 61 | if (type >= RemindType.SINGLE_MIN && type <= RemindType.SINGLE_WEEK) { 62 | singleRemindInterval.set(String.valueOf(ReminderUtils.getSingleRemindInterval(typeData))); 63 | singleRemindUnit.set(type); 64 | updateSelections(RemindType.SINGLE_REMIND); 65 | } else { 66 | updateSelections(type); 67 | } 68 | } 69 | 70 | public String getRemindUnitString(int unit) { 71 | switch (unit) { 72 | case RemindType.SINGLE_MIN: 73 | return getApplication().getString(R.string.remind_minutes); 74 | case RemindType.SINGLE_HOUR: 75 | return getApplication().getString(R.string.remind_hours); 76 | case RemindType.SINGLE_DAY: 77 | return getApplication().getString(R.string.remind_days); 78 | case RemindType.SINGLE_WEEK: 79 | return getApplication().getString(R.string.remind_weeks); 80 | default: 81 | return getApplication().getString(R.string.remind_minutes); 82 | } 83 | } 84 | 85 | public int getReminder() { 86 | return ReminderUtils.buildReminder(getRemindType(), Integer.parseInt(singleRemindInterval.get())); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/res/navigation/navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 18 | 24 | 30 | 36 | 42 | 43 | 44 | 49 | 50 | 55 | 62 | 63 | 64 | 69 | 70 | 71 | 76 | 77 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ils_noon.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/categorySelector/CategoryAdapter.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.categorySelector; 2 | 3 | import android.content.Context; 4 | import android.graphics.Typeface; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.CheckedTextView; 9 | 10 | import com.gwokhou.deadline.R; 11 | import com.gwokhou.deadline.data.Category; 12 | 13 | import java.util.List; 14 | 15 | import androidx.annotation.NonNull; 16 | import androidx.recyclerview.widget.RecyclerView; 17 | 18 | public class CategoryAdapter extends RecyclerView.Adapter { 19 | 20 | private CategorySelectDialogViewModel mViewModel; 21 | 22 | private List mCategoryItems; 23 | 24 | private CategoryItemActionListener mItemActionListener; 25 | 26 | private LayoutInflater mInflater; 27 | 28 | private Context mContext; 29 | 30 | class ViewHolder extends RecyclerView.ViewHolder { 31 | 32 | CheckedTextView categoryItem; 33 | 34 | ViewHolder(View view) { 35 | super(view); 36 | categoryItem = view.findViewById(R.id.selectable_category_item); 37 | } 38 | } 39 | 40 | CategoryAdapter(Context context, CategorySelectDialogViewModel viewModel) { 41 | mInflater = LayoutInflater.from(context); 42 | mContext = context; 43 | mViewModel = viewModel; 44 | } 45 | 46 | @NonNull 47 | @Override 48 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 49 | View itemView = mInflater.inflate(R.layout.item_category_select, parent, false); 50 | return new ViewHolder(itemView); 51 | } 52 | 53 | @Override 54 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 55 | if (mCategoryItems != null) { 56 | final Category current = mCategoryItems.get(position); 57 | holder.categoryItem.setText(current.getName()); 58 | 59 | if (mViewModel.currentSelected.equals(current.getName())) { 60 | holder.categoryItem.setChecked(true); 61 | holder.categoryItem.setTextColor(mContext.getResources().getColor(R.color.teal_600)); 62 | holder.categoryItem.setTypeface(null, Typeface.BOLD); 63 | holder.categoryItem.setCheckMarkDrawable(R.drawable.ic_done); 64 | } else { 65 | holder.categoryItem.setChecked(false); 66 | holder.categoryItem.setTextColor(mContext.getResources().getColor(R.color.black)); 67 | holder.categoryItem.setTypeface(null, Typeface.NORMAL); 68 | holder.categoryItem.setCheckMarkDrawable(null); 69 | } 70 | 71 | if (mItemActionListener != null) { 72 | holder.itemView.setOnClickListener(new View.OnClickListener() { 73 | @Override 74 | public void onClick(View v) { 75 | mItemActionListener.onItemClicked(current.getName()); 76 | } 77 | }); 78 | } 79 | } 80 | } 81 | 82 | 83 | @Override 84 | public int getItemCount() { 85 | if (mCategoryItems != null) { 86 | return mCategoryItems.size(); 87 | } else { 88 | return 0; 89 | } 90 | } 91 | 92 | public void setCategoryItems(List items) { 93 | mCategoryItems = items; 94 | notifyDataSetChanged(); 95 | } 96 | 97 | public void setItemActionListener(CategoryItemActionListener itemActionListener) { 98 | mItemActionListener = itemActionListener; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/util/ResourceValueUtils.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.util; 2 | 3 | import com.gwokhou.deadline.R; 4 | import com.gwokhou.deadline.dataType.FilterType; 5 | import com.gwokhou.deadline.dataType.RemindType; 6 | 7 | public class ResourceValueUtils { 8 | 9 | public static int getFilterChipTitle(String type) { 10 | if (type != null) { 11 | 12 | switch (type) { 13 | case FilterType.ALL_EVENTS: 14 | return R.string.chip_all; 15 | case FilterType.TODAY_EVENTS: 16 | return R.string.chip_today; 17 | case FilterType.NEXT_7_DAYS_EVENTS: 18 | return R.string.chip_next_7_days; 19 | case FilterType.COMPLETED_EVENTS: 20 | return R.string.chip_completed; 21 | case FilterType.INBOX: 22 | return R.string.chip_inbox; 23 | default: 24 | return 0; 25 | } 26 | } else { 27 | return R.string.chip_all; 28 | } 29 | } 30 | 31 | //PRIORITY = 0; 32 | //DUE_DATE = 1; 33 | //CREATION_DATE = 2; 34 | //ALPHA = 3; 35 | public static int getSortChipTitle(int grade) { 36 | int[] resArray = new int[]{ 37 | R.string.chip_sort_priority, 38 | R.string.chip_sort_due_date, 39 | R.string.chip_sort_creation_date, 40 | R.string.chip_sort_alpha 41 | }; 42 | return resArray[grade]; 43 | } 44 | 45 | //DAWN = 0; 46 | //MORNING = 1; 47 | //AFTERNOON = 2; 48 | //EVENING = 3; 49 | public static int getQuickViewTitle(int period) { 50 | int[] resArray = new int[]{ 51 | R.plurals.quick_view_dawn_desc, 52 | R.plurals.quick_view_morning_desc, 53 | R.plurals.quick_view_afternoon_desc, 54 | R.plurals.quick_view_evening_desc 55 | }; 56 | return resArray[period]; 57 | } 58 | 59 | public static int getQuickViewPic(int period) { 60 | int[] resArray = new int[]{ 61 | R.drawable.ils_morning, 62 | R.drawable.ils_morning, 63 | R.drawable.ils_noon, 64 | R.drawable.ils_night 65 | }; 66 | return resArray[period]; 67 | } 68 | 69 | public static int getReminderDesc(int type) { 70 | switch (type) { 71 | case RemindType.SINGLE_DUE_DATE: 72 | return R.string.single_remind_at_due_date; 73 | case RemindType.SINGLE_MIN: 74 | return R.plurals.single_remind_minutes_desc; 75 | case RemindType.SINGLE_HOUR: 76 | return R.plurals.single_remind_hours_desc; 77 | case RemindType.SINGLE_DAY: 78 | return R.plurals.single_remind_days_desc; 79 | case RemindType.SINGLE_WEEK: 80 | return R.plurals.single_remind_weeks_desc; 81 | case RemindType.REPEATED_EVERYDAY: 82 | return R.string.repeated_remind_everyday; 83 | case RemindType.REPEATED_ALWAYS: 84 | return R.string.repeated_remind_always; 85 | default: 86 | return R.string.single_remind_none; 87 | } 88 | } 89 | 90 | public static int getPriorityDesc(int priority) { 91 | int[] resArray = new int[]{ 92 | R.string.priority_none, 93 | R.string.priority_low, 94 | R.string.priority_medium, 95 | R.string.priority_high 96 | }; 97 | return resArray[priority]; 98 | } 99 | 100 | public static int getQuickViewBehDesc(int behavior) { 101 | int[] resArray = new int[]{ 102 | R.string.quick_view_show_every_time, 103 | // R.string.quick_view_show_once_per_day, 104 | R.string.quick_view_sticky 105 | }; 106 | return resArray[behavior]; 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwokhou/deadline/data/CategoryLocalDataSource.java: -------------------------------------------------------------------------------- 1 | package com.gwokhou.deadline.data; 2 | 3 | import com.gwokhou.deadline.util.AppExecutors; 4 | 5 | import java.util.List; 6 | 7 | import androidx.annotation.NonNull; 8 | 9 | public class CategoryLocalDataSource implements CategoryDataSource{ 10 | 11 | private static volatile CategoryLocalDataSource INSTANCE; 12 | 13 | private CategoriesDao mCategoriesDao; 14 | 15 | private AppExecutors mAppExecutors; 16 | 17 | private CategoryLocalDataSource(@NonNull AppExecutors appExecutors, 18 | @NonNull CategoriesDao categoriesDao) { 19 | mAppExecutors = appExecutors; 20 | mCategoriesDao = categoriesDao; 21 | } 22 | 23 | public static CategoryLocalDataSource getInstance(@NonNull AppExecutors appExecutors, 24 | @NonNull CategoriesDao categoriesDao) { 25 | if (INSTANCE == null) { 26 | synchronized (CategoryLocalDataSource.class) { 27 | if (INSTANCE == null) { 28 | INSTANCE = new CategoryLocalDataSource(appExecutors, categoriesDao); 29 | } 30 | } 31 | } 32 | return INSTANCE; 33 | } 34 | 35 | @Override 36 | public void getAllCategories(@NonNull final LoadCategoriesCallback callback) { 37 | Runnable runnable = new Runnable() { 38 | @Override 39 | public void run() { 40 | final List categories = mCategoriesDao.getAllCategories(); 41 | mAppExecutors.mainThread().execute(new Runnable() { 42 | @Override 43 | public void run() { 44 | if (categories.isEmpty()) { 45 | callback.onDataNotAvailable(); 46 | } else { 47 | callback.onCategoriesLoaded(categories); 48 | } 49 | } 50 | }); 51 | } 52 | }; 53 | 54 | mAppExecutors.diskIO().execute(runnable); 55 | } 56 | 57 | @Override 58 | public void getCategory(@NonNull final String categoryId, @NonNull final GetCategoryCallback callback) { 59 | Runnable runnable = new Runnable() { 60 | @Override 61 | public void run() { 62 | final Category category = mCategoriesDao.getCategoryById(categoryId); 63 | 64 | mAppExecutors.mainThread().execute(new Runnable() { 65 | @Override 66 | public void run() { 67 | if (category != null) { 68 | callback.onCategoryLoaded(category); 69 | } else { 70 | callback.onDataNotAvailable(); 71 | } 72 | } 73 | }); 74 | } 75 | }; 76 | 77 | mAppExecutors.diskIO().execute(runnable); 78 | } 79 | 80 | @Override 81 | public void saveCategory(@NonNull final Category category) { 82 | Runnable saveRunnable = new Runnable() { 83 | @Override 84 | public void run() { 85 | mCategoriesDao.insertCategory(category); 86 | } 87 | }; 88 | mAppExecutors.diskIO().execute(saveRunnable); 89 | } 90 | 91 | @Override 92 | public void deleteAllCategories() { 93 | Runnable deleteRunnable = new Runnable() { 94 | @Override 95 | public void run() { 96 | mCategoriesDao.deleteAllCategories(); 97 | } 98 | }; 99 | mAppExecutors.diskIO().execute(deleteRunnable); 100 | } 101 | 102 | @Override 103 | public void deleteCategory(@NonNull final String categoryId) { 104 | Runnable deleteRunnable = new Runnable() { 105 | @Override 106 | public void run() { 107 | mCategoriesDao.deleteCategoryById(categoryId); 108 | } 109 | }; 110 | mAppExecutors.diskIO().execute(deleteRunnable); 111 | } 112 | } 113 | --------------------------------------------------------------------------------