diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4f40844bf..bdc5c011c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -60,6 +60,8 @@ android:resource="@xml/widget_info"/> + + diff --git a/app/src/main/java/com/simplemobiletools/calendar/CalendarImpl.java b/app/src/main/java/com/simplemobiletools/calendar/CalendarImpl.java index 20422dc36..889c59813 100644 --- a/app/src/main/java/com/simplemobiletools/calendar/CalendarImpl.java +++ b/app/src/main/java/com/simplemobiletools/calendar/CalendarImpl.java @@ -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) { } diff --git a/app/src/main/java/com/simplemobiletools/calendar/DBHelper.java b/app/src/main/java/com/simplemobiletools/calendar/DBHelper.java index ff819e58d..2c6964be0 100644 --- a/app/src/main/java/com/simplemobiletools/calendar/DBHelper.java +++ b/app/src/main/java/com/simplemobiletools/calendar/DBHelper.java @@ -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); - mCallback.eventsDeleted(ids.length); + + 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 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(); } - mCallback.gotEvents(events); + + if (mCallback != null) + mCallback.gotEvents(events); + } + + 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; } public interface DBOperationsListener { - void eventInserted(); + void eventInserted(Event event); - void eventUpdated(); + void eventUpdated(Event event); void eventsDeleted(int cnt); diff --git a/app/src/main/java/com/simplemobiletools/calendar/NotificationPublisher.java b/app/src/main/java/com/simplemobiletools/calendar/NotificationPublisher.java new file mode 100644 index 000000000..5478a3f3a --- /dev/null +++ b/app/src/main/java/com/simplemobiletools/calendar/NotificationPublisher.java @@ -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(); + } +} diff --git a/app/src/main/java/com/simplemobiletools/calendar/activities/DayActivity.java b/app/src/main/java/com/simplemobiletools/calendar/activities/DayActivity.java index 114628f11..ecbdc0f5f 100644 --- a/app/src/main/java/com/simplemobiletools/calendar/activities/DayActivity.java +++ b/app/src/main/java/com/simplemobiletools/calendar/activities/DayActivity.java @@ -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) { } diff --git a/app/src/main/java/com/simplemobiletools/calendar/activities/EventActivity.java b/app/src/main/java/com/simplemobiletools/calendar/activities/EventActivity.java index c969a9a8d..21401e610 100644 --- a/app/src/main/java/com/simplemobiletools/calendar/activities/EventActivity.java +++ b/app/src/main/java/com/simplemobiletools/calendar/activities/EventActivity.java @@ -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(); } diff --git a/app/src/main/java/com/simplemobiletools/calendar/activities/MainActivity.java b/app/src/main/java/com/simplemobiletools/calendar/activities/MainActivity.java index 36db9568c..cdeeb9228 100644 --- a/app/src/main/java/com/simplemobiletools/calendar/activities/MainActivity.java +++ b/app/src/main/java/com/simplemobiletools/calendar/activities/MainActivity.java @@ -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)); - dayTV.setTextSize(mDayTextSize); - dayTV.setTextColor(mWeakTextColor); + if (dayTV != null) { + dayTV.setTextSize(mDayTextSize); + dayTV.setTextColor(mWeakTextColor); + } } } } diff --git a/app/src/main/java/com/simplemobiletools/calendar/models/Event.java b/app/src/main/java/com/simplemobiletools/calendar/models/Event.java index e326501de..4d0dd344a 100644 --- a/app/src/main/java/com/simplemobiletools/calendar/models/Event.java +++ b/app/src/main/java/com/simplemobiletools/calendar/models/Event.java @@ -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() + "}"; } } diff --git a/app/src/main/res/layout/activity_event.xml b/app/src/main/res/layout/activity_event.xml index ff78f1898..aee71c1b4 100644 --- a/app/src/main/res/layout/activity_event.xml +++ b/app/src/main/res/layout/activity_event.xml @@ -121,5 +121,17 @@ android:entries="@array/reminders" android:padding="@dimen/activity_margin"/> + + diff --git a/app/src/main/res/mipmap-hdpi/calendar.png b/app/src/main/res/mipmap-hdpi/calendar.png new file mode 100644 index 000000000..fd7bdc0a5 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/calendar.png differ diff --git a/app/src/main/res/mipmap-mdpi/calendar.png b/app/src/main/res/mipmap-mdpi/calendar.png new file mode 100644 index 000000000..4ddb16ee0 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/calendar.png differ diff --git a/app/src/main/res/mipmap-xhdpi/calendar.png b/app/src/main/res/mipmap-xhdpi/calendar.png new file mode 100644 index 000000000..2e3cd13c4 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/calendar.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/calendar.png b/app/src/main/res/mipmap-xxhdpi/calendar.png new file mode 100644 index 000000000..0e3a7cf03 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/calendar.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/calendar.png b/app/src/main/res/mipmap-xxxhdpi/calendar.png new file mode 100644 index 000000000..47247db25 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/calendar.png differ diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml index 17910c220..72a9e4262 100644 --- a/app/src/main/res/values/array.xml +++ b/app/src/main/res/values/array.xml @@ -3,7 +3,6 @@ @string/off @string/at_start - @string/ten_mins - @string/thirty_mins + @string/minutes_before diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 91798c74d..cac09c7d9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,8 +15,7 @@ Reminder Off At start - 10 mins before - 30 mins before + Minutes before Details diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index f39355514..99abf955b 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -50,6 +50,8 @@ 20sp +