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 | 
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 | 
29 | 
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 super T> 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 |
--------------------------------------------------------------------------------