mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-07-17 03:22:04 +00:00
Merge pull request #552 from TheHollidayInn/todo-local-notifications
Added notifications for todos
This commit is contained in:
commit
a7ea0d7714
18 changed files with 718 additions and 2 deletions
|
|
@ -17,6 +17,7 @@
|
|||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
|
||||
<application
|
||||
android:name=".HabiticaApplication"
|
||||
|
|
@ -120,6 +121,13 @@
|
|||
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
|
||||
<receiver android:process=":remote" android:name=".NotificationPublisher" />
|
||||
|
||||
<receiver android:process=":remote" android:name=".receivers.TaskReceiver"></receiver>
|
||||
<receiver android:name=".receivers.TaskAlarmBootReceiver" android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action._BOOT_COMPLETED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="com.habitrpg.android.habitica.fileprovider"
|
||||
|
|
|
|||
|
|
@ -344,6 +344,50 @@
|
|||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/task_reminders_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="30dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/reminders"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/reminders_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/new_reminder_edittext"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:hint="@string/start_date"
|
||||
android:textColor="@android:color/black"
|
||||
android:focusable="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/add_reminder_button"
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/add_checklist_item" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
|||
22
Habitica/res/layout/reminder_item.xml
Normal file
22
Habitica/res/layout/reminder_item.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/item_edittext"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@android:color/black"
|
||||
android:focusable="false" />
|
||||
|
||||
<Button
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/delete_item_button"
|
||||
android:text="x" />
|
||||
</LinearLayout>
|
||||
|
|
@ -80,6 +80,7 @@
|
|||
<string name="positive_habit_form">Positive ( + )</string>
|
||||
<string name="negative_habit_form">Negative ( - )</string>
|
||||
<string name="checklist">Checklist</string>
|
||||
<string name="reminders">Reminders</string>
|
||||
<string name="actions">Actions</string>
|
||||
|
||||
<string name="attributes">Attributes</string>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import com.magicmicky.habitrpgwrapper.lib.models.inventory.QuestContent;
|
|||
import com.magicmicky.habitrpgwrapper.lib.models.responses.FeedResponse;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.ChecklistItem;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.ItemData;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.RemindersItem;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.TaskList;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.TaskTag;
|
||||
|
|
@ -55,6 +56,7 @@ import com.magicmicky.habitrpgwrapper.lib.utils.MountListDeserializer;
|
|||
import com.magicmicky.habitrpgwrapper.lib.utils.PetListDeserializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.PurchasedDeserializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.QuestListDeserializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.RemindersItemSerializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.SkillDeserializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.TaskListDeserializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.TaskSerializer;
|
||||
|
|
@ -217,6 +219,7 @@ public class APIHelper implements Action1<Throwable> {
|
|||
.registerTypeAdapter(boolean.class, new BooleanAsIntAdapter())
|
||||
.registerTypeAdapter(skillListType, new SkillDeserializer())
|
||||
.registerTypeAdapter(ChecklistItem.class, new ChecklistItemSerializer())
|
||||
.registerTypeAdapter(RemindersItem.class, new RemindersItemSerializer())
|
||||
.registerTypeAdapter(TaskList.class, new TaskListDeserializer())
|
||||
.registerTypeAdapter(Purchases.class, new PurchasedDeserializer())
|
||||
.registerTypeAdapter(customizationListType, new CustomizationDeserializer())
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@ public class HabitDatabase {
|
|||
|
||||
public static final String NAME = "Habitica";
|
||||
|
||||
public static final int VERSION = 20;
|
||||
public static final int VERSION = 21;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import com.magicmicky.habitrpgwrapper.lib.models.inventory.QuestContent;
|
|||
import com.magicmicky.habitrpgwrapper.lib.models.responses.FeedResponse;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.ChecklistItem;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.ItemData;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.RemindersItem;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.TaskList;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.TaskTag;
|
||||
|
|
@ -47,6 +48,7 @@ import com.magicmicky.habitrpgwrapper.lib.utils.MountListDeserializer;
|
|||
import com.magicmicky.habitrpgwrapper.lib.utils.PetListDeserializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.PurchasedDeserializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.QuestListDeserializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.RemindersItemSerializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.SkillDeserializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.TaskListDeserializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.TaskSerializer;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.habitrpg.android.habitica.receivers;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.habitrpg.android.habitica.ui.helpers.TaskAlarmManager;
|
||||
|
||||
/**
|
||||
* Created by keithholliday on 5/29/16.
|
||||
*/
|
||||
public class TaskAlarmBootReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context arg0, Intent arg1) {
|
||||
TaskAlarmManager taskAlarmManager = TaskAlarmManager.getInstance(arg0);
|
||||
taskAlarmManager.scheduleAllSavedAlarms();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.habitrpg.android.habitica.receivers;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.habitrpg.android.habitica.R;
|
||||
import com.habitrpg.android.habitica.ui.activities.MainActivity;
|
||||
import com.habitrpg.android.habitica.ui.helpers.TaskAlarmManager;
|
||||
|
||||
/**
|
||||
* Created by keithholliday on 5/29/16.
|
||||
*/
|
||||
public class TaskReceiver extends BroadcastReceiver {
|
||||
|
||||
private Context context;
|
||||
|
||||
private String taskId;
|
||||
private String taskTitle;
|
||||
private TaskAlarmManager taskAlarmManager;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context arg0, Intent arg1) {
|
||||
context = arg0;
|
||||
taskAlarmManager = TaskAlarmManager.getInstance(context);
|
||||
|
||||
Bundle extras = arg1.getExtras();
|
||||
|
||||
if (extras != null) {
|
||||
taskTitle = extras.getString(TaskAlarmManager.TASK_NAME_INTENT_KEY);
|
||||
taskId = extras.getString(TaskAlarmManager.TASK_ID_INTENT_KEY);
|
||||
//This will set up the next reminders for dailies
|
||||
taskAlarmManager.addAlarmForTaskId(taskId);
|
||||
createNotification();
|
||||
}
|
||||
}
|
||||
|
||||
public void createNotification() {
|
||||
Intent intent = new Intent(context, MainActivity.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, (int) System.currentTimeMillis(), intent, 0);
|
||||
|
||||
Notification notification = new Notification.Builder(context)
|
||||
.setContentTitle(taskTitle)
|
||||
.setContentText(taskTitle).setSmallIcon(R.drawable.ic_gryphon)
|
||||
.setContentIntent(pendingIntent)
|
||||
.build();
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
|
||||
notification.flags |= Notification.FLAG_AUTO_CANCEL;
|
||||
|
||||
notificationManager.notify((int) System.currentTimeMillis(), notification);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,12 +8,15 @@ import com.habitrpg.android.habitica.events.TaskSaveEvent;
|
|||
import com.habitrpg.android.habitica.events.commands.DeleteTaskCommand;
|
||||
import com.habitrpg.android.habitica.ui.WrapContentRecyclerViewLayoutManager;
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.CheckListAdapter;
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.RemindersAdapter;
|
||||
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser;
|
||||
import com.habitrpg.android.habitica.ui.helpers.SimpleItemTouchHelperCallback;
|
||||
import com.habitrpg.android.habitica.ui.helpers.TaskAlarmManager;
|
||||
import com.habitrpg.android.habitica.ui.helpers.ViewHelper;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.Tag;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.ChecklistItem;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Days;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.RemindersItem;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.TaskTag;
|
||||
import com.raizlabs.android.dbflow.runtime.transaction.BaseTransaction;
|
||||
|
|
@ -25,6 +28,7 @@ import com.raizlabs.android.dbflow.sql.language.Set;
|
|||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
|
|
@ -37,7 +41,6 @@ import android.support.v7.widget.LinearLayoutManager;
|
|||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
|
@ -55,6 +58,7 @@ import android.widget.NumberPicker;
|
|||
import android.widget.Spinner;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.DecimalFormat;
|
||||
|
|
@ -67,6 +71,7 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
|
||||
import butterknife.BindView;
|
||||
import rx.Observable;
|
||||
|
|
@ -91,8 +96,11 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
|
|||
private NumberPicker frequencyPicker;
|
||||
private List<Tag> tags;
|
||||
private CheckListAdapter checklistAdapter;
|
||||
private RemindersAdapter remindersAdapter;
|
||||
private List<CheckBox> tagCheckBoxList;
|
||||
|
||||
private TaskAlarmManager taskAlarmManager;
|
||||
|
||||
@BindView(R.id.task_value_edittext)
|
||||
EditText taskValue;
|
||||
|
||||
|
|
@ -159,6 +167,18 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
|
|||
@BindView(R.id.add_checklist_button)
|
||||
Button button;
|
||||
|
||||
@BindView(R.id.task_reminders_wrapper)
|
||||
LinearLayout remindersWrapper;
|
||||
|
||||
@BindView(R.id.new_reminder_edittext)
|
||||
EditText newRemindersEditText;
|
||||
|
||||
@BindView(R.id.reminders_recycler_view)
|
||||
RecyclerView remindersRecyclerView;
|
||||
|
||||
@BindView(R.id.add_reminder_button)
|
||||
Button addReminderButton;
|
||||
|
||||
@BindView(R.id.emoji_toggle_btn0)
|
||||
ImageButton emojiToggle0;
|
||||
|
||||
|
|
@ -215,6 +235,8 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
|
|||
return;
|
||||
}
|
||||
|
||||
taskAlarmManager = TaskAlarmManager.getInstance(this);
|
||||
|
||||
dueDateListener = new DateEditTextListener(dueDatePickerText);
|
||||
startDateListener = new DateEditTextListener(startDatePickerText);
|
||||
|
||||
|
|
@ -255,6 +277,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
|
|||
taskWrapper.removeView(startDateLayout);
|
||||
|
||||
mainWrapper.removeView(checklistWrapper);
|
||||
mainWrapper.removeView(remindersWrapper);
|
||||
|
||||
positiveCheckBox.setChecked(true);
|
||||
negativeCheckBox.setChecked(true);
|
||||
|
|
@ -292,6 +315,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
|
|||
} else {
|
||||
|
||||
mainWrapper.removeView(checklistWrapper);
|
||||
mainWrapper.removeView(remindersWrapper);
|
||||
|
||||
difficultyWrapper.setVisibility(View.GONE);
|
||||
attributeWrapper.setVisibility(View.GONE);
|
||||
|
|
@ -314,6 +338,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
|
|||
|
||||
if (taskType.equals("todo") || taskType.equals("daily")) {
|
||||
createCheckListRecyclerView();
|
||||
createRemindersRecyclerView();
|
||||
}
|
||||
|
||||
// Emoji keyboard stuff
|
||||
|
|
@ -521,6 +546,65 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
|
|||
});
|
||||
}
|
||||
|
||||
private void createRemindersRecyclerView() {
|
||||
List<RemindersItem> reminders = new ArrayList<>();
|
||||
if (task != null && task.getReminders() != null) {
|
||||
reminders = task.getReminders();
|
||||
}
|
||||
remindersAdapter = new RemindersAdapter(reminders);
|
||||
|
||||
LinearLayoutManager llm = new LinearLayoutManager(this);
|
||||
llm.setOrientation(LinearLayoutManager.VERTICAL);
|
||||
|
||||
remindersRecyclerView.setLayoutManager(llm);
|
||||
remindersRecyclerView.setAdapter(remindersAdapter);
|
||||
|
||||
remindersRecyclerView.setLayoutManager(new WrapContentRecyclerViewLayoutManager(this));
|
||||
|
||||
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(remindersAdapter);
|
||||
ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(callback);
|
||||
mItemTouchHelper.attachToRecyclerView(remindersRecyclerView);
|
||||
|
||||
newRemindersEditText.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Calendar mcurrentTime = Calendar.getInstance();
|
||||
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = mcurrentTime.get(Calendar.MINUTE);
|
||||
TimePickerDialog mTimePicker;
|
||||
mTimePicker = new TimePickerDialog(TaskFormActivity.this, new TimePickerDialog.OnTimeSetListener() {
|
||||
@Override
|
||||
public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) {
|
||||
newRemindersEditText.setText( selectedHour + ":" + selectedMinute);
|
||||
}
|
||||
}, hour, minute, true);
|
||||
mTimePicker.setTitle("Select Time");
|
||||
mTimePicker.show();
|
||||
}
|
||||
});
|
||||
|
||||
addReminderButton.setOnClickListener(v -> {
|
||||
Date startDate = new Date(startDateListener.getCalendar().getTimeInMillis());
|
||||
|
||||
Date time = startDate;
|
||||
String reminderTimeString = newRemindersEditText.getText().toString();
|
||||
if (reminderTimeString.isEmpty()) return;
|
||||
String[] reminderTimeSplit = reminderTimeString.split(":");
|
||||
time.setHours(Integer.parseInt(reminderTimeSplit[0]));
|
||||
time.setMinutes(Integer.parseInt(reminderTimeSplit[1]));
|
||||
time.setSeconds(0);
|
||||
|
||||
RemindersItem item = new RemindersItem();
|
||||
UUID randomUUID = UUID.randomUUID();
|
||||
item.setId(randomUUID.toString());
|
||||
item.setStartDate(startDate);
|
||||
item.setTime(time);
|
||||
|
||||
remindersAdapter.addItem(item);
|
||||
newRemindersEditText.setText("");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void createTagsCheckBoxes() {
|
||||
int position = 0;
|
||||
|
|
@ -747,6 +831,12 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem
|
|||
}
|
||||
}
|
||||
|
||||
if (remindersAdapter != null) {
|
||||
if (remindersAdapter.getRemindersItems() != null) {
|
||||
task.setReminders(remindersAdapter.getRemindersItems());
|
||||
}
|
||||
}
|
||||
|
||||
if (task.text.isEmpty())
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,143 @@
|
|||
package com.habitrpg.android.habitica.ui.adapter.tasks;
|
||||
|
||||
import android.app.TimePickerDialog;
|
||||
import android.graphics.Color;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import com.github.data5tream.emojilib.EmojiEditText;
|
||||
import com.habitrpg.android.habitica.R;
|
||||
import com.habitrpg.android.habitica.ui.helpers.ItemTouchHelperAdapter;
|
||||
import com.habitrpg.android.habitica.ui.helpers.ItemTouchHelperViewHolder;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.RemindersItem;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.RemindersItem;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
/**
|
||||
* Created by keithholliday on 5/31/16.
|
||||
*/
|
||||
public class RemindersAdapter extends RecyclerView.Adapter<RemindersAdapter.ItemViewHolder>
|
||||
implements ItemTouchHelperAdapter {
|
||||
private final List<RemindersItem> reminders = new ArrayList<>();
|
||||
|
||||
public RemindersAdapter(List<RemindersItem> remindersInc) {
|
||||
reminders.addAll(remindersInc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.reminder_item, parent, false);
|
||||
ItemViewHolder itemViewHolder = new ItemViewHolder(view);
|
||||
return itemViewHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ItemViewHolder holder, int position) {
|
||||
Date time = reminders.get(position).getTime();
|
||||
holder.reminderItemTextView.setText(time.getHours() + ":" + time.getMinutes());
|
||||
}
|
||||
|
||||
public void addItem(RemindersItem item){
|
||||
reminders.add(item);
|
||||
notifyItemInserted(reminders.size() - 1);
|
||||
}
|
||||
|
||||
public List<RemindersItem> getRemindersItems(){
|
||||
return reminders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return reminders.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onItemDismiss(int position) {
|
||||
if(position >= 0 && position < reminders.size()){
|
||||
reminders.get(position).async().delete();
|
||||
reminders.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemMove(int fromPosition, int toPosition) {
|
||||
Collections.swap(reminders, fromPosition, toPosition);
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
}
|
||||
|
||||
public class ItemViewHolder extends RecyclerView.ViewHolder implements
|
||||
ItemTouchHelperViewHolder, Button.OnClickListener {
|
||||
|
||||
@BindView(R.id.item_edittext)
|
||||
EditText reminderItemTextView;
|
||||
|
||||
@BindView(R.id.delete_item_button)
|
||||
Button deleteButton;
|
||||
|
||||
public ItemViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
deleteButton.setOnClickListener(this);
|
||||
|
||||
reminderItemTextView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Calendar mcurrentTime = Calendar.getInstance();
|
||||
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = mcurrentTime.get(Calendar.MINUTE);
|
||||
TimePickerDialog mTimePicker;
|
||||
mTimePicker = new TimePickerDialog(v.getContext(), new TimePickerDialog.OnTimeSetListener() {
|
||||
@Override
|
||||
public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) {
|
||||
reminderItemTextView.setText( selectedHour + ":" + selectedMinute);
|
||||
|
||||
RemindersItem reminder = reminders.get(getAdapterPosition());
|
||||
Date time = reminder.getTime();
|
||||
time.setHours(selectedHour);
|
||||
time.setMinutes(selectedMinute);
|
||||
time.setSeconds(0);
|
||||
reminder.setTime(time);
|
||||
reminder.async().save();
|
||||
}
|
||||
}, hour, minute, true);
|
||||
mTimePicker.setTitle("Select Time");
|
||||
mTimePicker.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected() {
|
||||
itemView.setBackgroundColor(Color.LTGRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClear() {
|
||||
itemView.setBackgroundColor(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v == deleteButton) {
|
||||
RemindersAdapter.this.onItemDismiss(getAdapterPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
package com.habitrpg.android.habitica.ui.helpers;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.habitrpg.android.habitica.events.TaskSaveEvent;
|
||||
import com.habitrpg.android.habitica.receivers.TaskReceiver;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.RemindersItem;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
|
||||
import com.raizlabs.android.dbflow.sql.builder.Condition;
|
||||
import com.raizlabs.android.dbflow.sql.language.Select;
|
||||
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by keithholliday on 5/29/16.
|
||||
*/
|
||||
public class TaskAlarmManager {
|
||||
private static TaskAlarmManager instance = null;
|
||||
|
||||
private Context context;
|
||||
|
||||
public static final String TASK_ID_INTENT_KEY = "TASK_ID";
|
||||
public static final String TASK_NAME_INTENT_KEY = "TASK_NAME";
|
||||
|
||||
private TaskAlarmManager(Context context) {
|
||||
this.context = context;
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
||||
public static TaskAlarmManager getInstance(Context context){
|
||||
if(instance == null)
|
||||
{
|
||||
instance = new TaskAlarmManager(context);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onEvent(TaskSaveEvent evnt) {
|
||||
Task task = (Task) evnt.task;
|
||||
List<RemindersItem> reminders = task.getReminders();
|
||||
for (RemindersItem reminder : reminders) {
|
||||
if (task.getType().equals(Task.TYPE_DAILY)) {
|
||||
//Ensure that we set to the next available time
|
||||
reminder = this.setTimeForDailyReminder(reminder, task);
|
||||
}
|
||||
this.setAlarmForRemindersItem(reminder);
|
||||
reminder.async().save();
|
||||
}
|
||||
}
|
||||
|
||||
//This function is used from the TaskReceiver since we do not have access to the task
|
||||
//We currently only use this function to schedule the next reminder for dailies
|
||||
//We may be able to use repeating alarms instead of this in the future
|
||||
public void addAlarmForTaskId(String taskId) {
|
||||
List<Task> tasks = new Select()
|
||||
.from(Task.class)
|
||||
.where(Condition.column("id").eq(taskId))
|
||||
.queryList();
|
||||
|
||||
Task task = tasks.get(0);
|
||||
if (task == null) return;
|
||||
|
||||
if (!task.getType().equals(Task.TYPE_DAILY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<RemindersItem> reminders = task.getReminders();
|
||||
for (RemindersItem remindersItem : reminders) {
|
||||
//Ensure that we set to the next available time
|
||||
remindersItem = this.setTimeForDailyReminder(remindersItem, task);
|
||||
this.setAlarmForRemindersItem(remindersItem);
|
||||
remindersItem.async().save();
|
||||
}
|
||||
}
|
||||
|
||||
public void scheduleAllSavedAlarms() {
|
||||
List<RemindersItem> reminders = new Select()
|
||||
.from(RemindersItem.class)
|
||||
.where(Condition.column("time").greaterThan(new Date()))
|
||||
.orderBy(true, "time")
|
||||
.queryList();
|
||||
|
||||
for (RemindersItem remindersItem : reminders) {
|
||||
this.setAlarmForRemindersItem(remindersItem);
|
||||
}
|
||||
}
|
||||
|
||||
private RemindersItem setTimeForDailyReminder (RemindersItem remindersItem, Task task) {
|
||||
Date oldTime = remindersItem.getTime();
|
||||
Date newTime = task.getNextActiveDateAfter(oldTime);
|
||||
newTime.setHours(oldTime.getHours());
|
||||
newTime.setMinutes(oldTime.getMinutes());
|
||||
newTime.setSeconds(0);
|
||||
remindersItem.setTime(newTime);
|
||||
return remindersItem;
|
||||
}
|
||||
|
||||
private void setAlarmForRemindersItem(RemindersItem remindersItem) {
|
||||
Task reminderItemTask = remindersItem.getTask();
|
||||
Integer alarmId = remindersItem.getAlarmId();
|
||||
|
||||
if (alarmId == null) {
|
||||
alarmId = (int) System.currentTimeMillis();
|
||||
remindersItem.setAlarmId(alarmId);
|
||||
}
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
if (remindersItem.getTime().before(now)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(remindersItem.getTime());
|
||||
|
||||
Intent intent = new Intent(context, TaskReceiver.class);
|
||||
intent.putExtra(TASK_NAME_INTENT_KEY, reminderItemTask.getText());
|
||||
intent.putExtra(TASK_ID_INTENT_KEY, reminderItemTask.getId());
|
||||
|
||||
PendingIntent sender = PendingIntent.getBroadcast(context, alarmId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package com.magicmicky.habitrpgwrapper.lib.models.tasks;
|
||||
|
||||
import com.habitrpg.android.habitica.HabitDatabase;
|
||||
import com.habitrpg.android.habitica.database.ExcludeCheckListItem;
|
||||
import com.raizlabs.android.dbflow.annotation.Column;
|
||||
import com.raizlabs.android.dbflow.annotation.ForeignKey;
|
||||
import com.raizlabs.android.dbflow.annotation.ForeignKeyReference;
|
||||
import com.raizlabs.android.dbflow.annotation.PrimaryKey;
|
||||
import com.raizlabs.android.dbflow.annotation.Table;
|
||||
import com.raizlabs.android.dbflow.structure.BaseModel;
|
||||
import com.raizlabs.android.dbflow.structure.container.ForeignKeyContainer;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by keithholliday on 5/31/16.
|
||||
*/
|
||||
@Table(databaseName = HabitDatabase.NAME)
|
||||
public class RemindersItem extends BaseModel {
|
||||
@Column
|
||||
@PrimaryKey
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
private Date startDate;
|
||||
|
||||
@Column
|
||||
private Date time;
|
||||
|
||||
@Column
|
||||
private Integer alarmId;
|
||||
|
||||
@Column
|
||||
@ForeignKey(
|
||||
references = {@ForeignKeyReference(columnName = "task_id",
|
||||
columnType = String.class,
|
||||
foreignColumnName = "id")},
|
||||
saveForeignKeyModel = false)
|
||||
@ExcludeCheckListItem
|
||||
ForeignKeyContainer<Task> task;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getAlarmId() {
|
||||
return this.alarmId;
|
||||
}
|
||||
public void setAlarmId(Integer alarmId) {
|
||||
this.alarmId = alarmId;
|
||||
}
|
||||
|
||||
public Date getStartDate() {
|
||||
return startDate;
|
||||
}
|
||||
public void setStartDate(Date startDate) {
|
||||
this.startDate = startDate;
|
||||
}
|
||||
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
public void setTime(Date time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public Task getTask() {
|
||||
if (task != null) {
|
||||
return task.toModel();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTask(Task task) {
|
||||
this.task = new ForeignKeyContainer<>(Task.class);
|
||||
this.task.setModel(task);
|
||||
this.task.put("id", task.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
if (this.getId() == null) {
|
||||
return;
|
||||
}
|
||||
super.save();
|
||||
}
|
||||
}
|
||||
|
|
@ -78,6 +78,7 @@ public class Task extends BaseModel {
|
|||
public boolean completed;
|
||||
|
||||
public List<ChecklistItem> checklist;
|
||||
public List<RemindersItem> reminders;
|
||||
|
||||
|
||||
//dailies
|
||||
|
|
@ -291,6 +292,25 @@ public class Task extends BaseModel {
|
|||
this.checklist = checklist;
|
||||
}
|
||||
|
||||
@OneToMany(methods = {OneToMany.Method.SAVE, OneToMany.Method.DELETE}, variableName = "reminders")
|
||||
public List<RemindersItem> getReminders() {
|
||||
if(this.reminders == null) {
|
||||
this.reminders = new Select()
|
||||
.from(RemindersItem.class)
|
||||
.where(Condition.column("task_id").eq(this.id))
|
||||
.orderBy(true, "time")
|
||||
.queryList();
|
||||
}
|
||||
return this.reminders;
|
||||
}
|
||||
|
||||
public void setReminders(List<RemindersItem> reminders) {
|
||||
for (RemindersItem remindersItem : reminders) {
|
||||
remindersItem.setTask(this);
|
||||
}
|
||||
this.reminders = reminders;
|
||||
}
|
||||
|
||||
public Integer getCompletedChecklistCount() {
|
||||
Integer count = 0;
|
||||
for (ChecklistItem item : this.getChecklist()) {
|
||||
|
|
@ -387,11 +407,13 @@ public class Task extends BaseModel {
|
|||
}
|
||||
List<TaskTag> tmpTags = tags;
|
||||
List<ChecklistItem> tmpChecklist = checklist;
|
||||
List<RemindersItem> tmpReminders = reminders;
|
||||
|
||||
// remove them, so that the database don't add empty entries
|
||||
|
||||
tags = null;
|
||||
checklist = null;
|
||||
reminders = null;
|
||||
|
||||
if(repeat != null)
|
||||
repeat.task_id = this.id;
|
||||
|
|
@ -400,6 +422,7 @@ public class Task extends BaseModel {
|
|||
|
||||
tags = tmpTags;
|
||||
checklist = tmpChecklist;
|
||||
reminders = tmpReminders;
|
||||
|
||||
if (this.tags != null) {
|
||||
for (TaskTag tag : this.tags) {
|
||||
|
|
@ -407,6 +430,7 @@ public class Task extends BaseModel {
|
|||
tag.async().save();
|
||||
}
|
||||
}
|
||||
|
||||
int position = 0;
|
||||
if (this.checklist != null) {
|
||||
for (ChecklistItem item : this.checklist) {
|
||||
|
|
@ -418,6 +442,20 @@ public class Task extends BaseModel {
|
|||
position++;
|
||||
}
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
if (this.reminders != null) {
|
||||
for (RemindersItem item : this.reminders) {
|
||||
if(item.getTask() == null) {
|
||||
item.setTask(this);
|
||||
}
|
||||
if(item.getId() == null) {
|
||||
item.setId(this.id + "task-reminder" + index);
|
||||
}
|
||||
item.async().save();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -537,4 +575,35 @@ public class Task extends BaseModel {
|
|||
public Boolean isChecklistDisplayActive(int offset) {
|
||||
return this.isDisplayedActive(offset) && (this.checklist.size() != this.getCompletedChecklistCount());
|
||||
}
|
||||
|
||||
public Date getNextActiveDateAfter(Date oldTime) {
|
||||
Calendar today = new GregorianCalendar();
|
||||
today.set(Calendar.MILLISECOND, 0);
|
||||
today.set(Calendar.SECOND, 0);
|
||||
|
||||
Calendar newTime = new GregorianCalendar();
|
||||
newTime.setTime(oldTime);
|
||||
|
||||
if (this.getFrequency().equals(FREQUENCY_DAILY)) {
|
||||
TimeUnit timeUnit = TimeUnit.DAYS;
|
||||
long diffInMillies = newTime.getTimeInMillis() - today.getTimeInMillis();
|
||||
long daySinceStart = timeUnit.convert(diffInMillies, TimeUnit.MILLISECONDS);
|
||||
long daysUntilNextReminder = this.getEveryX() - (daySinceStart % this.getEveryX()) - 1;
|
||||
|
||||
if (newTime.before(today)) {
|
||||
daysUntilNextReminder += this.getEveryX();
|
||||
}
|
||||
|
||||
newTime.add(Calendar.DATE, (int) daysUntilNextReminder);
|
||||
} else {
|
||||
int nextActiveDayOfTheWeek = today.get(Calendar.DAY_OF_WEEK);
|
||||
while (!this.getRepeat().getForDay(nextActiveDayOfTheWeek) || newTime.before(today)) {
|
||||
if (nextActiveDayOfTheWeek == 6) nextActiveDayOfTheWeek = 0;
|
||||
nextActiveDayOfTheWeek += 1;
|
||||
newTime.add(Calendar.DATE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return newTime.getTime();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package com.magicmicky.habitrpgwrapper.lib.utils;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.RemindersItem;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Created by keithholliday on 6/4/16.
|
||||
*/
|
||||
public class RemindersItemSerializer
|
||||
implements JsonSerializer<RemindersItem> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(RemindersItem src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("id", src.getId());
|
||||
object.addProperty("startDate", src.getStartDate().toString());
|
||||
object.addProperty("time", src.getTime().toString());
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
|
@ -39,6 +39,7 @@ public class TaskSerializer implements JsonSerializer<Task> {
|
|||
obj.add("startDate", context.serialize(task.getStartDate()));
|
||||
obj.addProperty("streak", task.getStreak());
|
||||
obj.add("checklist", context.serialize(task.getChecklist()));
|
||||
obj.add("reminders", context.serialize(task.getReminders()));
|
||||
obj.addProperty("completed", task.getCompleted());
|
||||
break;
|
||||
case "todo":
|
||||
|
|
@ -48,6 +49,7 @@ public class TaskSerializer implements JsonSerializer<Task> {
|
|||
obj.add("date", context.serialize(task.getDueDate()));
|
||||
}
|
||||
obj.add("checklist", context.serialize(task.getChecklist()));
|
||||
obj.add("reminders", context.serialize(task.getReminders()));
|
||||
obj.addProperty("completed", task.getCompleted());
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ public class TaskAPITests extends BaseAPITests {
|
|||
task.setType(type);
|
||||
task.setTags(new ArrayList<>());
|
||||
task.setChecklist(new ArrayList<>());
|
||||
task.setReminders(new ArrayList<>());
|
||||
return task;
|
||||
}
|
||||
|
||||
|
|
|
|||
1
gradle/wrapper/gradle-wrapper.properties
vendored
1
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -4,3 +4,4 @@ distributionPath=wrapper/dists
|
|||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
|
||||
org.gradle.jvmargs=-Xmx3072M
|
||||
|
|
|
|||
Loading…
Reference in a new issue