implement event reminders

This commit is contained in:
tibbi 2016-07-07 00:19:07 +02:00
parent ad7a08eaeb
commit 4e294d89d8
17 changed files with 221 additions and 33 deletions

View File

@ -60,6 +60,8 @@
android:resource="@xml/widget_info"/>
</receiver>
<receiver android:name=".NotificationPublisher"/>
</application>
</manifest>

View File

@ -107,12 +107,12 @@ public class CalendarImpl implements DBHelper.DBOperationsListener {
}
@Override
public void eventInserted() {
public void eventInserted(Event event) {
}
@Override
public void eventUpdated() {
public void eventUpdated(Event event) {
}

View File

@ -16,7 +16,7 @@ public class DBHelper extends SQLiteOpenHelper {
private static DBOperationsListener mCallback;
private static final String DB_NAME = "events.db";
private static final int DB_VERSION = 1;
private static final int DB_VERSION = 2;
private static final String TABLE_NAME = "events";
private static final String COL_ID = "id";
@ -24,6 +24,7 @@ public class DBHelper extends SQLiteOpenHelper {
private static final String COL_END_TS = "end_ts";
private static final String COL_TITLE = "title";
private static final String COL_DESCRIPTION = "description";
private static final String COL_REMINDER_MINUTES = "reminder_minutes";
public static DBHelper newInstance(Context context, DBOperationsListener callback) {
mCallback = callback;
@ -42,19 +43,25 @@ public class DBHelper extends SQLiteOpenHelper {
COL_START_TS + " INTEGER," +
COL_END_TS + " INTEGER," +
COL_TITLE + " TEXT," +
COL_DESCRIPTION + " TEXT" +
COL_DESCRIPTION + " TEXT," +
COL_REMINDER_MINUTES + " INTEGER" +
")");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion == 1) {
db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + COL_REMINDER_MINUTES + " INTEGER DEFAULT -1");
}
}
public void insert(Event event) {
final ContentValues values = fillContentValues(event);
mDb.insert(TABLE_NAME, null, values);
mCallback.eventInserted();
long id = mDb.insert(TABLE_NAME, null, values);
event.setId((int) id);
if (mCallback != null)
mCallback.eventInserted(event);
}
public void update(Event event) {
@ -62,7 +69,9 @@ public class DBHelper extends SQLiteOpenHelper {
final String selection = COL_ID + " = ?";
final String[] selectionArgs = {String.valueOf(event.getId())};
mDb.update(TABLE_NAME, values, selection, selectionArgs);
mCallback.eventUpdated();
if (mCallback != null)
mCallback.eventUpdated(event);
}
private ContentValues fillContentValues(Event event) {
@ -71,24 +80,20 @@ public class DBHelper extends SQLiteOpenHelper {
values.put(COL_END_TS, event.getEndTS());
values.put(COL_TITLE, event.getTitle());
values.put(COL_DESCRIPTION, event.getDescription());
values.put(COL_REMINDER_MINUTES, event.getReminderMinutes());
return values;
}
public void deleteEvent(int id) {
final String selection = COL_ID + " = ?";
final String[] selectionArgs = {String.valueOf(id)};
mDb.delete(TABLE_NAME, selection, selectionArgs);
mCallback.eventsDeleted(1);
}
public void deleteEvents(String[] ids) {
final String selection = COL_ID + " IN (?)";
mDb.delete(TABLE_NAME, selection, ids);
if (mCallback != null)
mCallback.eventsDeleted(ids.length);
}
public void getEvents(int fromTS, int toTS) {
final String[] projection = {COL_ID, COL_START_TS, COL_END_TS, COL_TITLE, COL_DESCRIPTION};
final String[] projection = {COL_ID, COL_START_TS, COL_END_TS, COL_TITLE, COL_DESCRIPTION, COL_REMINDER_MINUTES};
List<Event> events = new ArrayList<>();
final String selection = COL_START_TS + " <= ? AND " + COL_END_TS + " >= ?";
final String[] selectionArgs = {String.valueOf(toTS), String.valueOf(fromTS)};
@ -101,18 +106,40 @@ public class DBHelper extends SQLiteOpenHelper {
final int endTS = cursor.getInt(cursor.getColumnIndex(COL_END_TS));
final String title = cursor.getString(cursor.getColumnIndex(COL_TITLE));
final String description = cursor.getString(cursor.getColumnIndex(COL_DESCRIPTION));
events.add(new Event(id, startTS, endTS, title, description));
final int reminderMinutes = cursor.getInt(cursor.getColumnIndex(COL_REMINDER_MINUTES));
events.add(new Event(id, startTS, endTS, title, description, reminderMinutes));
} while (cursor.moveToNext());
}
cursor.close();
}
if (mCallback != null)
mCallback.gotEvents(events);
}
public interface DBOperationsListener {
void eventInserted();
public Event getEvent(int id) {
final String[] projection = {COL_START_TS, COL_END_TS, COL_TITLE, COL_DESCRIPTION, COL_REMINDER_MINUTES};
final String selection = COL_ID + " = ?";
final String[] selectionArgs = {String.valueOf(id)};
final Cursor cursor = mDb.query(TABLE_NAME, projection, selection, selectionArgs, null, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
final int startTS = cursor.getInt(cursor.getColumnIndex(COL_START_TS));
final int endTS = cursor.getInt(cursor.getColumnIndex(COL_END_TS));
final String title = cursor.getString(cursor.getColumnIndex(COL_TITLE));
final String description = cursor.getString(cursor.getColumnIndex(COL_DESCRIPTION));
final int reminderMinutes = cursor.getInt(cursor.getColumnIndex(COL_REMINDER_MINUTES));
cursor.close();
return new Event(id, startTS, endTS, title, description, reminderMinutes);
}
}
return null;
}
void eventUpdated();
public interface DBOperationsListener {
void eventInserted(Event event);
void eventUpdated(Event event);
void eventsDeleted(int cnt);

View File

@ -0,0 +1,49 @@
package com.simplemobiletools.calendar;
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 com.simplemobiletools.calendar.activities.EventActivity;
import com.simplemobiletools.calendar.models.Event;
public class NotificationPublisher extends BroadcastReceiver {
public static String EVENT_ID = "event_id";
public void onReceive(Context context, Intent intent) {
final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
int id = intent.getIntExtra(EVENT_ID, -1);
if (id == -1)
return;
final Event event = DBHelper.newInstance(context, null).getEvent(id);
if (event == null || event.getReminderMinutes() == -1)
return;
final PendingIntent pendingIntent = getPendingIntent(context, event);
final String startTime = Formatter.getTime(event.getStartTS());
final String endTime = Formatter.getTime(event.getEndTS());
final String title = event.getTitle();
final Notification notification = getNotification(context, pendingIntent, startTime + " - " + endTime + " " + title);
notificationManager.notify(id, notification);
}
private PendingIntent getPendingIntent(Context context, Event event) {
final Intent intent = new Intent(context, EventActivity.class);
intent.putExtra(Constants.EVENT, event);
return PendingIntent.getActivity(context, 0, intent, 0);
}
private Notification getNotification(Context context, PendingIntent pendingIntent, String content) {
final Notification.Builder builder = new Notification.Builder(context);
builder.setContentTitle(context.getResources().getString(R.string.app_name));
builder.setContentText(content);
builder.setSmallIcon(R.mipmap.calendar);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
return builder.build();
}
}

View File

@ -189,12 +189,12 @@ public class DayActivity extends AppCompatActivity
}
@Override
public void eventInserted() {
public void eventInserted(Event event) {
}
@Override
public void eventUpdated() {
public void eventUpdated(Event event) {
}

View File

@ -1,15 +1,20 @@
package com.simplemobiletools.calendar.activities;
import android.app.AlarmManager;
import android.app.DatePickerDialog;
import android.app.PendingIntent;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatSpinner;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.TextView;
@ -18,6 +23,7 @@ import android.widget.TimePicker;
import com.simplemobiletools.calendar.Constants;
import com.simplemobiletools.calendar.DBHelper;
import com.simplemobiletools.calendar.Formatter;
import com.simplemobiletools.calendar.NotificationPublisher;
import com.simplemobiletools.calendar.R;
import com.simplemobiletools.calendar.Utils;
import com.simplemobiletools.calendar.models.Event;
@ -39,11 +45,13 @@ public class EventActivity extends AppCompatActivity implements DBHelper.DBOpera
@BindView(R.id.event_end_time) TextView mEndTime;
@BindView(R.id.event_title) EditText mTitleET;
@BindView(R.id.event_description) EditText mDescriptionET;
@BindView(R.id.event_reminder_other) EditText mReminderOtherET;
@BindView(R.id.event_reminder) AppCompatSpinner mReminder;
private static DateTime mEventStartDateTime;
private static DateTime mEventEndDateTime;
private static Event mEvent;
private static boolean mWasReminderInit;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -55,6 +63,7 @@ public class EventActivity extends AppCompatActivity implements DBHelper.DBOpera
if (intent == null)
return;
mWasReminderInit = false;
final Event event = (Event) intent.getSerializableExtra(Constants.EVENT);
if (event != null) {
mEvent = event;
@ -72,6 +81,7 @@ public class EventActivity extends AppCompatActivity implements DBHelper.DBOpera
updateStartTime();
updateEndDate();
updateEndTime();
setupReminder();
}
private void setupEditEvent() {
@ -93,9 +103,42 @@ public class EventActivity extends AppCompatActivity implements DBHelper.DBOpera
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
}
private void showKeyboard(EditText et) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(et, InputMethodManager.SHOW_IMPLICIT);
}
private void setupReminder() {
switch (mEvent.getReminderMinutes()) {
case -1:
mReminder.setSelection(0);
break;
case 0:
mReminder.setSelection(1);
break;
default:
mReminder.setSelection(2);
mReminderOtherET.setVisibility(View.VISIBLE);
mReminderOtherET.setText(String.valueOf(mEvent.getReminderMinutes()));
break;
}
}
@OnItemSelected(R.id.event_reminder)
public void handleReminder() {
if (!mWasReminderInit) {
mWasReminderInit = true;
return;
}
if (mReminder.getSelectedItemPosition() == mReminder.getCount() - 1) {
mReminderOtherET.setVisibility(View.VISIBLE);
mReminderOtherET.requestFocus();
showKeyboard(mReminderOtherET);
} else {
mReminderOtherET.setVisibility(View.GONE);
hideKeyboard();
}
}
@Override
@ -147,10 +190,12 @@ public class EventActivity extends AppCompatActivity implements DBHelper.DBOpera
final DBHelper dbHelper = DBHelper.newInstance(getApplicationContext(), this);
final String description = mDescriptionET.getText().toString().trim();
final int reminderMinutes = getReminderMinutes();
mEvent.setStartTS(startTS);
mEvent.setEndTS(endTS);
mEvent.setTitle(title);
mEvent.setDescription(description);
mEvent.setReminderMinutes(reminderMinutes);
if (mEvent.getId() == 0) {
dbHelper.insert(mEvent);
} else {
@ -158,6 +203,21 @@ public class EventActivity extends AppCompatActivity implements DBHelper.DBOpera
}
}
private int getReminderMinutes() {
switch (mReminder.getSelectedItemPosition()) {
case 0:
return -1;
case 1:
return 0;
default:
final String value = mReminderOtherET.getText().toString().trim();
if (value.isEmpty())
return 0;
return Integer.valueOf(value);
}
}
private void updateStartDate() {
mStartDate.setText(Formatter.getEventDate(mEventStartDateTime));
}
@ -245,14 +305,34 @@ public class EventActivity extends AppCompatActivity implements DBHelper.DBOpera
}
}
private void handleNotification(Event event) {
if (event.getReminderMinutes() == -1) {
return;
}
final long delayFromNow = (long) event.getStartTS() * 1000 - event.getReminderMinutes() * 60000 - System.currentTimeMillis();
if (delayFromNow < 0) {
return;
}
final long notifInMs = SystemClock.elapsedRealtime() + delayFromNow;
final Intent intent = new Intent(this, NotificationPublisher.class);
intent.putExtra(NotificationPublisher.EVENT_ID, event.getId());
final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, event.getId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, notifInMs, pendingIntent);
}
@Override
public void eventInserted() {
public void eventInserted(Event event) {
handleNotification(event);
Utils.showToast(getApplicationContext(), R.string.event_added);
finish();
}
@Override
public void eventUpdated() {
public void eventUpdated(Event event) {
handleNotification(event);
Utils.showToast(getApplicationContext(), R.string.event_updated);
finish();
}

View File

@ -213,8 +213,10 @@ public class MainActivity extends AppCompatActivity implements Calendar {
private void setupLabels() {
for (int i = 0; i < 7; i++) {
final TextView dayTV = (TextView) findViewById(mRes.getIdentifier("label_" + i, "id", mPackageName));
if (dayTV != null) {
dayTV.setTextSize(mDayTextSize);
dayTV.setTextColor(mWeakTextColor);
}
}
}
}

View File

@ -4,11 +4,12 @@ import java.io.Serializable;
public class Event implements Serializable {
private static final long serialVersionUID = -32456795132354616L;
private final int mId;
private int mId;
private int mStartTS;
private int mEndTS;
private String mTitle;
private String mDescription;
private int mReminderMinutes;
public Event() {
mId = 0;
@ -16,20 +17,26 @@ public class Event implements Serializable {
mEndTS = 0;
mTitle = "";
mDescription = "";
mReminderMinutes = -1;
}
public Event(int id, int startTS, int endTS, String title, String description) {
public Event(int id, int startTS, int endTS, String title, String description, int reminerMinutes) {
mId = id;
mStartTS = startTS;
mEndTS = endTS;
mTitle = title;
mDescription = description;
mReminderMinutes = reminerMinutes;
}
public int getId() {
return mId;
}
public void setId(int id) {
mId = id;
}
public int getStartTS() {
return mStartTS;
}
@ -62,6 +69,14 @@ public class Event implements Serializable {
mDescription = description;
}
public int getReminderMinutes() {
return mReminderMinutes;
}
public void setReminderMinutes(int reminderMinutes) {
mReminderMinutes = reminderMinutes;
}
@Override
public String toString() {
return "Event {" +
@ -70,6 +85,7 @@ public class Event implements Serializable {
", endTS=" + getEndTS() +
", title=" + getTitle() +
", description=" + getDescription() +
", reminderMinutes=" + getReminderMinutes() +
"}";
}
}

View File

@ -121,5 +121,17 @@
android:entries="@array/reminders"
android:padding="@dimen/activity_margin"/>
<EditText
android:id="@+id/event_reminder_other"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/event_reminder_label"
android:layout_toRightOf="@+id/event_reminder"
android:digits="0123456789"
android:inputType="number"
android:minEms="5"
android:textSize="@dimen/day_text_size"
android:visibility="invisible"/>
</RelativeLayout>
</ScrollView>

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -3,7 +3,6 @@
<string-array name="reminders">
<item>@string/off</item>
<item>@string/at_start</item>
<item>@string/ten_mins</item>
<item>@string/thirty_mins</item>
<item>@string/minutes_before</item>
</string-array>
</resources>

View File

@ -15,8 +15,7 @@
<string name="reminder">Reminder</string>
<string name="off">Off</string>
<string name="at_start">At start</string>
<string name="ten_mins">10 mins before</string>
<string name="thirty_mins">30 mins before</string>
<string name="minutes_before">Minutes before</string>
<!-- Day details -->
<string name="details">Details</string>

View File

@ -50,6 +50,8 @@
<item name="android:textSize">20sp</item>
</style>
<style name="EditTextStyle" parent="@android:style/Widget.TextView"/>
<style name="SpinnerItem" parent="@android:style/Widget.TextView">
<item name="android:paddingRight">@dimen/activity_margin</item>
</style>