From fcf877635b819849944685d269b4e69f27c5175a Mon Sep 17 00:00:00 2001 From: Alex Styl Date: Sat, 4 Mar 2017 13:36:12 +0000 Subject: [PATCH 1/7] WIP: show static events on widget --- mobile/src/main/AndroidManifest.xml | 2 +- .../addevent/ContactEventsLoader.java | 2 +- .../addevent/ContactOperations.java | 2 +- .../contact/AndroidContactsProvider.java | 1 + .../contact/ContactsProvider.java | 2 + .../DailyReminderIntentService.java | 2 +- .../com/alexstyl/specialdates/date/Date.java | 1 + .../date/DateDisplayStringCreator.java | 8 ++ .../datedetails/PeopleEventsQuery.java | 10 -- .../PeopleNamedaysCalculator.java | 6 +- ....java => StaticEventsContentProvider.java} | 2 +- .../search/PeopleEventsSearch.java | 2 +- .../service/PeopleEventsProvider.java | 107 +++++++++--------- .../upcoming/UpcomingEventsLoader.java | 2 +- .../widgetprovider/TodayWidgetProvider.java | 36 +++--- .../search/PeopleEventsSearchTest.java | 2 +- 16 files changed, 101 insertions(+), 86 deletions(-) delete mode 100644 mobile/src/main/java/com/alexstyl/specialdates/datedetails/PeopleEventsQuery.java rename mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/{PeopleEventsContentProvider.java => StaticEventsContentProvider.java} (98%) diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml index eb172c4a..99aa00e2 100644 --- a/mobile/src/main/AndroidManifest.xml +++ b/mobile/src/main/AndroidManifest.xml @@ -177,7 +177,7 @@ loadInBackground() { private List createModelsFor(Contact contact) { List existingViewModels; List contactEvents = new ArrayList<>(); - List contactEventsOnDate = peopleEventsProvider.getCelebrationDateFor(TimePeriod.aYearFromNow()); + List contactEventsOnDate = peopleEventsProvider.getContactEventsFor(TimePeriod.aYearFromNow()); List existingTypes = new ArrayList<>(); for (ContactEvent contactEvent : contactEventsOnDate) { if (contactEvent.getContact().getContactID() == contact.getContactID() && isEditable(contactEvent)) { diff --git a/mobile/src/main/java/com/alexstyl/specialdates/addevent/ContactOperations.java b/mobile/src/main/java/com/alexstyl/specialdates/addevent/ContactOperations.java index 53e11577..677e2b8d 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/addevent/ContactOperations.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/addevent/ContactOperations.java @@ -101,7 +101,7 @@ private int rawContactID(Contact contact) { private List getAllDeviceEventsFor(Contact contact) { List contactEvents = new ArrayList<>(); - List contactEventsOnDate = peopleEventsProvider.getCelebrationDateFor(TimePeriod.aYearFromNow()); + List contactEventsOnDate = peopleEventsProvider.getContactEventsFor(TimePeriod.aYearFromNow()); for (ContactEvent contactEvent : contactEventsOnDate) { Contact dbContact = contactEvent.getContact(); if (dbContact.getContactID() == contact.getContactID() && contactEvent.getType() != StandardEventType.NAMEDAY) { diff --git a/mobile/src/main/java/com/alexstyl/specialdates/contact/AndroidContactsProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/contact/AndroidContactsProvider.java index bf4ee241..e53f3081 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/contact/AndroidContactsProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/contact/AndroidContactsProvider.java @@ -41,6 +41,7 @@ private AndroidContactsProvider(ContactCache cache, DeviceContactFactor this.deviceContactsQuery = deviceContactsQuery; } + @Override public Contact getOrCreateContact(long contactID) throws ContactNotFoundException { Contact deviceContact = cache.getContact(contactID); if (deviceContact == null) { diff --git a/mobile/src/main/java/com/alexstyl/specialdates/contact/ContactsProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/contact/ContactsProvider.java index 52e8af2a..2fb70906 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/contact/ContactsProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/contact/ContactsProvider.java @@ -4,4 +4,6 @@ public interface ContactsProvider { List fetchAllDeviceContacts(); + + Contact getOrCreateContact(long contactId) throws ContactNotFoundException; } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/dailyreminder/DailyReminderIntentService.java b/mobile/src/main/java/com/alexstyl/specialdates/dailyreminder/DailyReminderIntentService.java index c37446a0..571157bf 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/dailyreminder/DailyReminderIntentService.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/dailyreminder/DailyReminderIntentService.java @@ -66,7 +66,7 @@ protected void onHandleIntent(Intent intent) { Date today = getDayDateToDisplay(); if (hasContactPermission()) { - List celebrationDate = provider.getCelebrationDateFor(TimePeriod.between(today, today)); + List celebrationDate = provider.getContactEventsFor(TimePeriod.between(today, today)); if (containsAnyContactEvents(celebrationDate)) { notifier.forDailyReminder(today, celebrationDate); } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/date/Date.java b/mobile/src/main/java/com/alexstyl/specialdates/date/Date.java index e3bba3f6..f77a5d33 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/date/Date.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/date/Date.java @@ -148,4 +148,5 @@ public int hashCode() { public String toString() { return DateDisplayStringCreator.INSTANCE.stringOf(this); } + } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/date/DateDisplayStringCreator.java b/mobile/src/main/java/com/alexstyl/specialdates/date/DateDisplayStringCreator.java index a3f2ee7d..893fea6a 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/date/DateDisplayStringCreator.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/date/DateDisplayStringCreator.java @@ -21,6 +21,14 @@ public String stringOf(Date date) { return str.toString(); } + public String stringOfNoYear(Date date) { + StringBuilder str = new StringBuilder(); + addMonth(date, str); + str.append(SEPARATOR); + addDayOfMonth(date, str); + return str.toString(); + } + private void addYear(Date date, StringBuilder str) { if (date.hasYear()) { str.append(date.getYear()); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/PeopleEventsQuery.java b/mobile/src/main/java/com/alexstyl/specialdates/datedetails/PeopleEventsQuery.java deleted file mode 100644 index 0d7210de..00000000 --- a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/PeopleEventsQuery.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.alexstyl.specialdates.datedetails; - -import com.alexstyl.specialdates.events.database.PeopleEventsContract; - -public class PeopleEventsQuery { - private static final String BIRTHDAYS_ONLY_AND = PeopleEventsContract.PeopleEvents.EVENT_TYPE + " = " + PeopleEventsContract.PeopleEvents.TYPE_BIRTHDAY + " AND "; - - public static final String SELECT = PeopleEventsContract.PeopleEvents.DATE + " = ?"; - public static final String SELECT_ONLY_BIRTHDAYS = BIRTHDAYS_ONLY_AND + SELECT; -} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java b/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java index 36873f61..c5ab38bd 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java @@ -59,6 +59,10 @@ public List loadDeviceStaticNamedays() { return namedayEvents; } + public List loadSpecialNamedaysOn(Date date) { + return loadSpecialNamedaysBetween(TimePeriod.between(date, date)); + } + public List loadSpecialNamedaysBetween(TimePeriod timeDuration) { List namedayEvents = new ArrayList<>(); for (Contact contact : contactsProvider.fetchAllDeviceContacts()) { @@ -91,7 +95,7 @@ private NameCelebrations getSpecialNamedaysOf(String firstName) { return namedayCalendar.getSpecialNamedaysFor(firstName); } - public NamedayCalendar getNamedayCalendar() { + private NamedayCalendar getNamedayCalendar() { NamedayLocale locale = namedayPreferences.getSelectedLanguage(); return namedayCalendarProvider.loadNamedayCalendarForLocale(locale, Date.CURRENT_YEAR); } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleEventsContentProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/StaticEventsContentProvider.java similarity index 98% rename from mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleEventsContentProvider.java rename to mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/StaticEventsContentProvider.java index b9034d9a..faedab00 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleEventsContentProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/StaticEventsContentProvider.java @@ -28,7 +28,7 @@ import com.alexstyl.specialdates.util.DateParser; import com.novoda.notils.exception.DeveloperError; -public class PeopleEventsContentProvider extends ContentProvider { +public class StaticEventsContentProvider extends ContentProvider { private static final int CODE_PEOPLE_EVENTS = 10; private EventSQLiteOpenHelper eventSQLHelper; diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/PeopleEventsSearch.java b/mobile/src/main/java/com/alexstyl/specialdates/search/PeopleEventsSearch.java index ddf6046c..70251ead 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/search/PeopleEventsSearch.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/search/PeopleEventsSearch.java @@ -27,7 +27,7 @@ List searchForContacts(String searchQuery, int counter) { searchQuery = searchQuery.trim(); HashMapList events = new HashMapList<>(); TimePeriod between = TimePeriod.aYearFromNow(); - List contactEventsOnDate = peopleEventsProvider.getCelebrationDateFor(between); + List contactEventsOnDate = peopleEventsProvider.getContactEventsFor(between); int size = 0; for (ContactEvent contactEvent : contactEventsOnDate) { Contact contact = contactEvent.getContact(); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java index 544c8319..ad33f1ae 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java @@ -5,16 +5,20 @@ import android.database.Cursor; import android.database.MergeCursor; import android.net.Uri; +import android.support.annotation.NonNull; import com.alexstyl.specialdates.ErrorTracker; import com.alexstyl.specialdates.Optional; +import com.alexstyl.specialdates.SQLArgumentBuilder; +import com.alexstyl.specialdates.contact.AndroidContactsProvider; import com.alexstyl.specialdates.contact.Contact; import com.alexstyl.specialdates.contact.ContactNotFoundException; -import com.alexstyl.specialdates.contact.AndroidContactsProvider; +import com.alexstyl.specialdates.contact.ContactsProvider; import com.alexstyl.specialdates.date.ContactEvent; import com.alexstyl.specialdates.date.Date; +import com.alexstyl.specialdates.date.DateDisplayStringCreator; import com.alexstyl.specialdates.date.DateParseException; -import com.alexstyl.specialdates.datedetails.PeopleEventsQuery; +import com.alexstyl.specialdates.date.TimePeriod; import com.alexstyl.specialdates.events.database.EventColumns; import com.alexstyl.specialdates.events.database.EventTypeId; import com.alexstyl.specialdates.events.database.PeopleEventsContract; @@ -24,9 +28,7 @@ import com.alexstyl.specialdates.events.peopleevents.ContactEvents; import com.alexstyl.specialdates.events.peopleevents.EventType; import com.alexstyl.specialdates.events.peopleevents.PeopleNamedaysCalculator; -import com.alexstyl.specialdates.SQLArgumentBuilder; import com.alexstyl.specialdates.events.peopleevents.StandardEventType; -import com.alexstyl.specialdates.date.TimePeriod; import com.alexstyl.specialdates.util.DateParser; import com.novoda.notils.exception.DeveloperError; import com.novoda.notils.logger.simple.Log; @@ -48,7 +50,7 @@ public class PeopleEventsProvider { PeopleEvents.EVENT_TYPE, }; - private final AndroidContactsProvider contactsProvider; + private final ContactsProvider contactsProvider; private final ContentResolver resolver; private final NamedayPreferences namedayPreferences; private final PeopleNamedaysCalculator peopleNamedaysCalculator; @@ -68,7 +70,7 @@ public static PeopleEventsProvider newInstance(Context context) { return new PeopleEventsProvider(contactsProvider, resolver, namedayPreferences, peopleNamedaysCalculator, customEventProvider); } - private PeopleEventsProvider(AndroidContactsProvider contactsProvider, + private PeopleEventsProvider(ContactsProvider contactsProvider, ContentResolver resolver, NamedayPreferences namedayPreferences, PeopleNamedaysCalculator peopleNamedaysCalculator, CustomEventProvider customEventProvider) { @@ -91,7 +93,8 @@ public List getCelebrationDateOn(Date date) { } - public List getCelebrationDateFor(TimePeriod timeDuration) { + public List getContactEventsFor(TimePeriod timeDuration) { + // todo this one List contactEvents = fetchStaticEventsBetween(timeDuration); if (namedayPreferences.isEnabled()) { @@ -182,22 +185,50 @@ private ContactEvent getContactEventFrom(Cursor cursor) throws ContactNotFoundEx } public ContactEvents getCelebrationsClosestTo(Date date) { - Date closestDate = findClosestDateTo(date); - return getCelebrationDateFor(closestDate); + Optional closestStaticDate = findClosestStaticEventDateFrom(date); + ContactEvents staticEvents = getStaticContactEventsFor(closestStaticDate.get()); + +// if (namedayPreferences.isEnabled()) { +// Optional closestDynamicDate = findClosestDynamicEventDateTo(date); +// if (closestDynamicDate.isPresent()) { +// List namedaysContactEvents = peopleNamedaysCalculator.loadSpecialNamedaysOn(closestDynamicDate.get()); +// return ContactEvents.createFrom(closestDynamicDate.get(), namedaysContactEvents); +// } +// } + + return staticEvents; } - ContactEvents getCelebrationDateFor(Date date) { + private Optional findClosestStaticEventDateFrom(Date date) { + Cursor cursor = queryDateClosestTo(date); + try { + if (cursor.moveToFirst()) { + Date closestDate = getDateFrom(cursor); + return new Optional<>(closestDate); + } + return Optional.absent(); + } finally { + cursor.close(); + } + } + + private Optional findClosestDynamicEventDateTo(Date date) { + List contactEvents = peopleNamedaysCalculator.loadSpecialNamedaysBetween(TimePeriod.between(date, date.addWeek(4))); + if (contactEvents.size() > 0) { + return new Optional<>(contactEvents.get(0).getDate()); + } + return Optional.absent(); + } + + private ContactEvents getStaticContactEventsFor(Date date) { List contactEvents = new ArrayList<>(); Cursor cursor = resolver.query( PeopleEvents.CONTENT_URI, null, - getSelection(), + PeopleEvents.DATE + " = ?", getSelectArgs(date), PeopleEvents.CONTACT_ID ); - if (isInvalid(cursor)) { - throw new DeveloperError("Cursor was invalid"); - } while (cursor.moveToNext()) { long contactId = getContactIdFrom(cursor); @@ -216,37 +247,27 @@ ContactEvents getCelebrationDateFor(Date date) { return ContactEvents.createFrom(date, contactEvents); } - private Date findClosestDateTo(Date date) { - Cursor cursor = queryDateClosestTo(date); - if (isInvalid(cursor)) { - throw new DeveloperError("Cursor was invalid"); - } - - Date dateFrom; - if (cursor.moveToFirst()) { - dateFrom = getDateFrom(cursor); - } else { - dateFrom = date; - } - cursor.close(); - return dateFrom; - } - private static final Uri PEOPLE_EVENTS = PeopleEvents.CONTENT_URI; private Cursor queryDateClosestTo(Date date) { + // select * from annual_events WHERE substr(date,3) >= '03-04' ORDER BY substr(date,3) asc LIMIT 1 return resolver.query( PEOPLE_EVENTS, PEOPLE_PROJECTION, - PeopleEvents.DATE + " >= ?", - thePassing(date), - PeopleEvents.DATE + " ASC LIMIT 1" + substr(PeopleEvents.DATE) + " >= ?", + monthAndDayOf(date), + substr(PeopleEvents.DATE) + " ASC LIMIT 1" ); } - private String[] thePassing(Date date) { + @NonNull + private String substr(String datetete) { + return "substr(" + datetete + ",3) "; + } + + private String[] monthAndDayOf(Date date) { return new String[]{ - date.toShortDate() + DateDisplayStringCreator.INSTANCE.stringOfNoYear(date) }; } @@ -254,18 +275,6 @@ private String[] getSelectArgs(Date date) { return new String[]{date.toShortDate()}; } - private String getSelection() { - if (namedaysAreEnabled()) { - return PeopleEventsQuery.SELECT; - } else { - return PeopleEventsQuery.SELECT_ONLY_BIRTHDAYS; - } - } - - private boolean namedaysAreEnabled() { - return namedayPreferences.isEnabled(); - } - private static void throwIfInvalid(Cursor cursor) { if (isInvalid(cursor)) { throw new RuntimeException("Invalid cursor"); @@ -326,8 +335,4 @@ private static boolean isALegitEventId(long deviceEventId) { return deviceEventId == -1; } - public List getEventsFor(Contact contact) { - List contactEvents = new ArrayList<>(); - return contactEvents; - } } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/UpcomingEventsLoader.java b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/UpcomingEventsLoader.java index 09e2fddd..8bbd2dc6 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/UpcomingEventsLoader.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/UpcomingEventsLoader.java @@ -72,7 +72,7 @@ public List loadInBackground() { } private List calculateEventsBetween(TimePeriod period) { - List contactEvents = peopleEventsProvider.getCelebrationDateFor(period); + List contactEvents = peopleEventsProvider.getContactEventsFor(period); Resources resources = getContext().getResources(); AndroidColorResources colorResources = new AndroidColorResources(resources); AndroidStringResources stringResources = new AndroidStringResources(resources); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/widgetprovider/TodayWidgetProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/widgetprovider/TodayWidgetProvider.java index ad5ac9dd..c12c9933 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/widgetprovider/TodayWidgetProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/widgetprovider/TodayWidgetProvider.java @@ -25,13 +25,6 @@ public class TodayWidgetProvider extends AppWidgetProvider { private WidgetImageLoader imageLoader; private StringResources stringResources; - StringResources getOrCreateStringResources(Resources resources) { - if (stringResources == null) { - stringResources = new AndroidStringResources(resources); - } - return stringResources; - } - @Override public void onEnabled(Context context) { super.onEnabled(context); @@ -44,23 +37,40 @@ public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); } + private void getOrCreateImageLoader(Context context) { + if (imageLoader == null) { + imageLoader = WidgetImageLoader.newInstance(context.getResources(), AppWidgetManager.getInstance(context)); + } + } + @Override public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) { - new QueryUpcomingPeoplEventsTask(PeopleEventsProvider.newInstance(context)) { @Override void onLoaded(ContactEvents contactEvents) { - if (contactEvents.size() > 0) { + if (hasEvents(contactEvents)) { updateForDate(context, appWidgetManager, appWidgetIds, contactEvents); } else { onUpdateNoEventsFound(context, appWidgetManager, appWidgetIds); } } + + private boolean hasEvents(ContactEvents contactEvents) { + return contactEvents.size() > 0; + } }.execute(); } + StringResources getOrCreateStringResources(Resources resources) { + if (stringResources == null) { + stringResources = new AndroidStringResources(resources); + } + return stringResources; + } + private void updateForDate(Context context, final AppWidgetManager appWidgetManager, int[] appWidgetIds, ContactEvents contactEvents) { - Date date = contactEvents.getDate(); + Date eventDate = contactEvents.getDate(); + Date date = Date.on(eventDate.getDayOfMonth(), eventDate.getMonth(), Date.today().getYear()); Intent intent = DateDetailsActivity.getStartIntent(context, date); PendingIntent pendingIntent = PendingIntent.getActivity( @@ -146,10 +156,4 @@ public static void updateWidgets(Context context) { context.sendBroadcast(intent); } - private void getOrCreateImageLoader(Context context) { - if (imageLoader == null) { - imageLoader = WidgetImageLoader.newInstance(context.getResources(), AppWidgetManager.getInstance(context)); - } - } - } diff --git a/mobile/src/test/java/com/alexstyl/specialdates/search/PeopleEventsSearchTest.java b/mobile/src/test/java/com/alexstyl/specialdates/search/PeopleEventsSearchTest.java index 3710a494..392eb7c6 100644 --- a/mobile/src/test/java/com/alexstyl/specialdates/search/PeopleEventsSearchTest.java +++ b/mobile/src/test/java/com/alexstyl/specialdates/search/PeopleEventsSearchTest.java @@ -43,7 +43,7 @@ public void setUp() { .addNamedayFor(MIMOZA, JANUARY_1st) .build(); - when(mockProvider.getCelebrationDateFor(aYearFromNow())).thenReturn(contactEvents); + when(mockProvider.getContactEventsFor(aYearFromNow())).thenReturn(contactEvents); } private static TimePeriod aYearFromNow() { From 2a872315ed079ca25f068e3400cea24ec36b3c25 Mon Sep 17 00:00:00 2001 From: Alex Styl Date: Sat, 4 Mar 2017 21:24:30 +0000 Subject: [PATCH 2/7] Combine static events with dynamic if needed --- ...tEvents.java => ContactEventsOnADate.java} | 14 +++--- .../service/PeopleEventsProvider.java | 44 +++++++++++++------ .../specialdates/wear/WearSyncService.java | 8 ++-- .../QueryUpcomingPeoplEventsTask.java | 10 ++--- .../widgetprovider/TodayWidgetProvider.java | 8 ++-- .../events/ContactActionTest.java | 10 ++--- 6 files changed, 56 insertions(+), 38 deletions(-) rename mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/{ContactEvents.java => ContactEventsOnADate.java} (75%) diff --git a/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/ContactEvents.java b/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/ContactEventsOnADate.java similarity index 75% rename from mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/ContactEvents.java rename to mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/ContactEventsOnADate.java index 8fdc5bec..3ba6697b 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/ContactEvents.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/ContactEventsOnADate.java @@ -8,15 +8,15 @@ import java.util.Collections; import java.util.List; -public class ContactEvents { +public class ContactEventsOnADate { private final Date date; private final List contactEventList; private final List contacts; - public static ContactEvents createFrom(Date date, List contactEvent) { + public static ContactEventsOnADate createFrom(Date date, List contactEvent) { List contacts = getContactsIn(contactEvent); - return new ContactEvents(date, contactEvent, contacts); + return new ContactEventsOnADate(date, contactEvent, contacts); } private static List getContactsIn(List contactEvent) { @@ -30,7 +30,7 @@ private static List getContactsIn(List contactEvent) { return Collections.unmodifiableList(contacts); } - private ContactEvents(Date date, List contactEventList, List contacts) { + private ContactEventsOnADate(Date date, List contactEventList, List contacts) { this.date = date; this.contactEventList = contactEventList; this.contacts = contacts; @@ -49,10 +49,10 @@ public Date getDate() { } public List getContacts() { - return Collections.unmodifiableList(contacts); + return contacts; } - public int getContactCount() { - return contacts.size(); + public List getEvents() { + return contactEventList; } } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java index ad33f1ae..82fa14e4 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java @@ -16,6 +16,7 @@ import com.alexstyl.specialdates.contact.ContactsProvider; import com.alexstyl.specialdates.date.ContactEvent; import com.alexstyl.specialdates.date.Date; +import com.alexstyl.specialdates.date.DateComparator; import com.alexstyl.specialdates.date.DateDisplayStringCreator; import com.alexstyl.specialdates.date.DateParseException; import com.alexstyl.specialdates.date.TimePeriod; @@ -25,7 +26,7 @@ import com.alexstyl.specialdates.events.database.PeopleEventsContract.PeopleEvents; import com.alexstyl.specialdates.events.namedays.NamedayPreferences; import com.alexstyl.specialdates.events.namedays.calendar.resource.NamedayCalendarProvider; -import com.alexstyl.specialdates.events.peopleevents.ContactEvents; +import com.alexstyl.specialdates.events.peopleevents.ContactEventsOnADate; import com.alexstyl.specialdates.events.peopleevents.EventType; import com.alexstyl.specialdates.events.peopleevents.PeopleNamedaysCalculator; import com.alexstyl.specialdates.events.peopleevents.StandardEventType; @@ -184,19 +185,29 @@ private ContactEvent getContactEventFrom(Cursor cursor) throws ContactNotFoundEx return new ContactEvent(eventId, eventType, date, contact); } - public ContactEvents getCelebrationsClosestTo(Date date) { + public ContactEventsOnADate getCelebrationsClosestTo(Date date) { Optional closestStaticDate = findClosestStaticEventDateFrom(date); - ContactEvents staticEvents = getStaticContactEventsFor(closestStaticDate.get()); + ContactEventsOnADate staticEvents = getStaticContactEventsFor(closestStaticDate.get()); + ContactEventsOnADate dynamicEvents = getDyanmicEvents(date, closestStaticDate); -// if (namedayPreferences.isEnabled()) { -// Optional closestDynamicDate = findClosestDynamicEventDateTo(date); -// if (closestDynamicDate.isPresent()) { -// List namedaysContactEvents = peopleNamedaysCalculator.loadSpecialNamedaysOn(closestDynamicDate.get()); -// return ContactEvents.createFrom(closestDynamicDate.get(), namedaysContactEvents); -// } -// } + if (DateComparator.INSTANCE.compare(closestStaticDate.get(), dynamicEvents.getDate()) == 0) { + return ContactEventsOnADate.createFrom(dynamicEvents.getDate(), combine(dynamicEvents.getEvents(), staticEvents.getEvents())); + } else if (DateComparator.INSTANCE.compare(closestStaticDate.get(), dynamicEvents.getDate()) > 0) { + return dynamicEvents; + } else { + return staticEvents; + } + } - return staticEvents; + private ContactEventsOnADate getDyanmicEvents(Date date, Optional closestStaticDate) { + if (namedayPreferences.isEnabled()) { + Optional closestDynamicDate = findClosestDynamicEventDateTo(date); + if (closestDynamicDate.isPresent()) { + List namedaysContactEvents = peopleNamedaysCalculator.loadSpecialNamedaysOn(closestDynamicDate.get()); + return ContactEventsOnADate.createFrom(closestDynamicDate.get(), namedaysContactEvents); + } + } + return ContactEventsOnADate.createFrom(closestStaticDate.get(), Collections.emptyList()); } private Optional findClosestStaticEventDateFrom(Date date) { @@ -220,7 +231,7 @@ private Optional findClosestDynamicEventDateTo(Date date) { return Optional.absent(); } - private ContactEvents getStaticContactEventsFor(Date date) { + private ContactEventsOnADate getStaticContactEventsFor(Date date) { List contactEvents = new ArrayList<>(); Cursor cursor = resolver.query( PeopleEvents.CONTENT_URI, @@ -244,7 +255,7 @@ private ContactEvents getStaticContactEventsFor(Date date) { } } cursor.close(); - return ContactEvents.createFrom(date, contactEvents); + return ContactEventsOnADate.createFrom(date, contactEvents); } private static final Uri PEOPLE_EVENTS = PeopleEvents.CONTENT_URI; @@ -335,4 +346,11 @@ private static boolean isALegitEventId(long deviceEventId) { return deviceEventId == -1; } + private static List combine(List listA, List listB) { + List contactEvents = new ArrayList<>(); + contactEvents.addAll(listA); + contactEvents.addAll(listB); + return contactEvents; + } + } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/wear/WearSyncService.java b/mobile/src/main/java/com/alexstyl/specialdates/wear/WearSyncService.java index 480a3e10..01da347c 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/wear/WearSyncService.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/wear/WearSyncService.java @@ -6,7 +6,7 @@ import com.alexstyl.specialdates.contact.Contact; import com.alexstyl.specialdates.date.Date; -import com.alexstyl.specialdates.events.peopleevents.ContactEvents; +import com.alexstyl.specialdates.events.peopleevents.ContactEventsOnADate; import com.alexstyl.specialdates.service.PeopleEventsProvider; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.wearable.PutDataMapRequest; @@ -29,7 +29,7 @@ public static void startService(Context context) { @Override protected void onHandleIntent(Intent intent) { - ContactEvents contactEvents = fetchContactEvents(); + ContactEventsOnADate contactEvents = fetchContactEvents(); if (contactEvents.size() == 0) { return; } @@ -44,13 +44,13 @@ protected void onHandleIntent(Intent intent) { } } - private ContactEvents fetchContactEvents() { + private ContactEventsOnADate fetchContactEvents() { PeopleEventsProvider eventsProvider = PeopleEventsProvider.newInstance(this); Date today = Date.today(); return eventsProvider.getCelebrationsClosestTo(today); } - private PutDataRequest createDataRequest(ContactEvents contactEvents) { + private PutDataRequest createDataRequest(ContactEventsOnADate contactEvents) { PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(SharedConstants.NEXT_CONTACT_EVENTS_PATH); putDataMapRequest.getDataMap().putStringArrayList(SharedConstants.KEY_CONTACTS_NAMES, getContactsNameListFrom(contactEvents.getContacts())); putDataMapRequest.getDataMap().putLong(SharedConstants.KEY_DATE, contactEvents.getDate().toMillis()); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/widgetprovider/QueryUpcomingPeoplEventsTask.java b/mobile/src/main/java/com/alexstyl/specialdates/widgetprovider/QueryUpcomingPeoplEventsTask.java index 2e3e7f9c..431ae52a 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/widgetprovider/QueryUpcomingPeoplEventsTask.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/widgetprovider/QueryUpcomingPeoplEventsTask.java @@ -2,11 +2,11 @@ import android.os.AsyncTask; -import com.alexstyl.specialdates.events.peopleevents.ContactEvents; +import com.alexstyl.specialdates.events.peopleevents.ContactEventsOnADate; import com.alexstyl.specialdates.date.Date; import com.alexstyl.specialdates.service.PeopleEventsProvider; -abstract class QueryUpcomingPeoplEventsTask extends AsyncTask { +abstract class QueryUpcomingPeoplEventsTask extends AsyncTask { private final PeopleEventsProvider eventsProvider; @@ -15,16 +15,16 @@ abstract class QueryUpcomingPeoplEventsTask extends AsyncTask 0; } }.execute(); @@ -68,7 +68,7 @@ StringResources getOrCreateStringResources(Resources resources) { return stringResources; } - private void updateForDate(Context context, final AppWidgetManager appWidgetManager, int[] appWidgetIds, ContactEvents contactEvents) { + private void updateForDate(Context context, final AppWidgetManager appWidgetManager, int[] appWidgetIds, ContactEventsOnADate contactEvents) { Date eventDate = contactEvents.getDate(); Date date = Date.on(eventDate.getDayOfMonth(), eventDate.getMonth(), Date.today().getYear()); Intent intent = DateDetailsActivity.getStartIntent(context, date); diff --git a/mobile/src/test/java/com/alexstyl/specialdates/events/ContactActionTest.java b/mobile/src/test/java/com/alexstyl/specialdates/events/ContactActionTest.java index 9a7ce4f4..ff357e4b 100644 --- a/mobile/src/test/java/com/alexstyl/specialdates/events/ContactActionTest.java +++ b/mobile/src/test/java/com/alexstyl/specialdates/events/ContactActionTest.java @@ -6,7 +6,7 @@ import com.alexstyl.specialdates.contact.Contact; import com.alexstyl.specialdates.date.ContactEvent; import com.alexstyl.specialdates.date.Date; -import com.alexstyl.specialdates.events.peopleevents.ContactEvents; +import com.alexstyl.specialdates.events.peopleevents.ContactEventsOnADate; import com.alexstyl.specialdates.events.peopleevents.StandardEventType; import java.util.ArrayList; @@ -29,7 +29,7 @@ public class ContactActionTest { @Test public void testTheSameDateIsReturned() throws Exception { Date expectedDate = Date.on(1, 1, 1990); - ContactEvents events = ContactEvents.createFrom(expectedDate, ANY_CONTACTS); + ContactEventsOnADate events = ContactEventsOnADate.createFrom(expectedDate, ANY_CONTACTS); Date actualDate = events.getDate(); assertThat(actualDate).isEqualTo(expectedDate); @@ -41,7 +41,7 @@ public void testContactCorrectContactIsReturned() { ArrayList contactEvent = new ArrayList<>(); contactEvent.add(EVENT_ONE); - ContactEvents events = ContactEvents.createFrom(date, contactEvent); + ContactEventsOnADate events = ContactEventsOnADate.createFrom(date, contactEvent); List contacts = events.getContacts(); assertThat(contacts.get(0)).isEqualTo(CONTACT_ONE); @@ -53,7 +53,7 @@ public void testContactsAreCorrectlyReturned() { ArrayList contactEvent = new ArrayList<>(); contactEvent.add(EVENT_ONE); contactEvent.add(EVENT_TWO); - ContactEvents events = ContactEvents.createFrom(date, contactEvent); + ContactEventsOnADate events = ContactEventsOnADate.createFrom(date, contactEvent); List contacts = events.getContacts(); assertThat(contacts).contains(CONTACT_ONE); @@ -66,7 +66,7 @@ public void testReturnedContactsSizeIsCorrect() { ArrayList contactEvent = new ArrayList<>(); contactEvent.add(EVENT_ONE); contactEvent.add(EVENT_TWO); - ContactEvents events = ContactEvents.createFrom(date, contactEvent); + ContactEventsOnADate events = ContactEventsOnADate.createFrom(date, contactEvent); List contacts = events.getContacts(); assertThat(contacts.size()).isEqualTo(2); From b70cb9260a0d0c971fe9b0ee7646128018dd64d5 Mon Sep 17 00:00:00 2001 From: Alex Styl Date: Wed, 8 Mar 2017 21:42:05 +0000 Subject: [PATCH 3/7] Write test around PeopleEventsProvider --- .../PeopleNamedaysCalculator.java | 14 +- .../service/PeopleEventsProvider.java | 262 ++---------------- .../service/StaticPeopleEventsProvider.java | 207 ++++++++++++++ .../specialdates/ContactEventFixture.java | 30 ++ ...der.java => TestContactEventsBuilder.java} | 8 +- .../search/PeopleEventsSearchTest.java | 4 +- .../service/PeopleEventsProviderTest.java | 70 +++++ 7 files changed, 341 insertions(+), 254 deletions(-) create mode 100644 mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java create mode 100644 mobile/src/test/java/com/alexstyl/specialdates/ContactEventFixture.java rename mobile/src/test/java/com/alexstyl/specialdates/{TestContactEventBuilder.java => TestContactEventsBuilder.java} (82%) create mode 100644 mobile/src/test/java/com/alexstyl/specialdates/service/PeopleEventsProviderTest.java diff --git a/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java b/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java index c5ab38bd..e724eef1 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java @@ -3,15 +3,15 @@ import com.alexstyl.specialdates.DisplayName; import com.alexstyl.specialdates.Optional; import com.alexstyl.specialdates.contact.Contact; -import com.alexstyl.specialdates.contact.AndroidContactsProvider; +import com.alexstyl.specialdates.contact.ContactsProvider; import com.alexstyl.specialdates.date.ContactEvent; import com.alexstyl.specialdates.date.Date; +import com.alexstyl.specialdates.date.TimePeriod; import com.alexstyl.specialdates.events.namedays.NameCelebrations; import com.alexstyl.specialdates.events.namedays.NamedayLocale; import com.alexstyl.specialdates.events.namedays.NamedayPreferences; import com.alexstyl.specialdates.events.namedays.calendar.NamedayCalendar; import com.alexstyl.specialdates.events.namedays.calendar.resource.NamedayCalendarProvider; -import com.alexstyl.specialdates.date.TimePeriod; import java.util.ArrayList; import java.util.HashSet; @@ -22,11 +22,13 @@ public final class PeopleNamedaysCalculator { private static final Optional NO_DEVICE_EVENT_ID = Optional.absent(); private final NamedayPreferences namedayPreferences; private final NamedayCalendarProvider namedayCalendarProvider; - private final AndroidContactsProvider contactsProvider; + private final ContactsProvider contactsProvider; - public PeopleNamedaysCalculator(NamedayPreferences namedayPreferences, - NamedayCalendarProvider namedayCalendarProvider, - AndroidContactsProvider contactsProvider) { + public PeopleNamedaysCalculator( + NamedayPreferences namedayPreferences, + NamedayCalendarProvider namedayCalendarProvider, + ContactsProvider contactsProvider + ) { this.namedayPreferences = namedayPreferences; this.namedayCalendarProvider = namedayCalendarProvider; this.contactsProvider = contactsProvider; diff --git a/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java index 82fa14e4..3ee08324 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java @@ -2,37 +2,21 @@ import android.content.ContentResolver; import android.content.Context; -import android.database.Cursor; -import android.database.MergeCursor; -import android.net.Uri; -import android.support.annotation.NonNull; -import com.alexstyl.specialdates.ErrorTracker; import com.alexstyl.specialdates.Optional; -import com.alexstyl.specialdates.SQLArgumentBuilder; import com.alexstyl.specialdates.contact.AndroidContactsProvider; -import com.alexstyl.specialdates.contact.Contact; -import com.alexstyl.specialdates.contact.ContactNotFoundException; import com.alexstyl.specialdates.contact.ContactsProvider; import com.alexstyl.specialdates.date.ContactEvent; import com.alexstyl.specialdates.date.Date; import com.alexstyl.specialdates.date.DateComparator; -import com.alexstyl.specialdates.date.DateDisplayStringCreator; import com.alexstyl.specialdates.date.DateParseException; import com.alexstyl.specialdates.date.TimePeriod; -import com.alexstyl.specialdates.events.database.EventColumns; -import com.alexstyl.specialdates.events.database.EventTypeId; -import com.alexstyl.specialdates.events.database.PeopleEventsContract; -import com.alexstyl.specialdates.events.database.PeopleEventsContract.PeopleEvents; import com.alexstyl.specialdates.events.namedays.NamedayPreferences; import com.alexstyl.specialdates.events.namedays.calendar.resource.NamedayCalendarProvider; import com.alexstyl.specialdates.events.peopleevents.ContactEventsOnADate; -import com.alexstyl.specialdates.events.peopleevents.EventType; import com.alexstyl.specialdates.events.peopleevents.PeopleNamedaysCalculator; -import com.alexstyl.specialdates.events.peopleevents.StandardEventType; import com.alexstyl.specialdates.util.DateParser; import com.novoda.notils.exception.DeveloperError; -import com.novoda.notils.logger.simple.Log; import java.util.ArrayList; import java.util.Collections; @@ -40,22 +24,10 @@ public class PeopleEventsProvider { - private static final String DATE_FROM = "substr(" + PeopleEvents.DATE + ",-5) >= ?"; - private static final String DATE_TO = "substr(" + PeopleEvents.DATE + ",-5) <= ?"; - private static final String DATE_BETWEEN_IGNORING_YEAR = DATE_FROM + " AND " + DATE_TO; - private static final String[] PEOPLE_PROJECTION = new String[]{PeopleEvents.DATE}; - private static final String[] PROJECTION = { - PeopleEvents.CONTACT_ID, - PeopleEvents.DEVICE_EVENT_ID, - PeopleEvents.DATE, - PeopleEvents.EVENT_TYPE, - }; - private final ContactsProvider contactsProvider; - private final ContentResolver resolver; private final NamedayPreferences namedayPreferences; private final PeopleNamedaysCalculator peopleNamedaysCalculator; - private final CustomEventProvider customEventProvider; + private final StaticPeopleEventsProvider staticEventsProvider; public static PeopleEventsProvider newInstance(Context context) { AndroidContactsProvider contactsProvider = AndroidContactsProvider.get(context); @@ -68,23 +40,29 @@ public static PeopleEventsProvider newInstance(Context context) { contactsProvider ); CustomEventProvider customEventProvider = new CustomEventProvider(resolver); - return new PeopleEventsProvider(contactsProvider, resolver, namedayPreferences, peopleNamedaysCalculator, customEventProvider); + StaticPeopleEventsProvider staticEventsProvider = new StaticPeopleEventsProvider(resolver, contactsProvider, customEventProvider); + return new PeopleEventsProvider( + contactsProvider, + namedayPreferences, + peopleNamedaysCalculator, + staticEventsProvider + ); } - private PeopleEventsProvider(ContactsProvider contactsProvider, - ContentResolver resolver, - NamedayPreferences namedayPreferences, - PeopleNamedaysCalculator peopleNamedaysCalculator, CustomEventProvider customEventProvider) { + PeopleEventsProvider(ContactsProvider contactsProvider, + NamedayPreferences namedayPreferences, + PeopleNamedaysCalculator peopleNamedaysCalculator, + StaticPeopleEventsProvider staticEventsProvider + ) { this.contactsProvider = contactsProvider; - this.resolver = resolver; + this.staticEventsProvider = staticEventsProvider; this.namedayPreferences = namedayPreferences; this.peopleNamedaysCalculator = peopleNamedaysCalculator; - this.customEventProvider = customEventProvider; } public List getCelebrationDateOn(Date date) { TimePeriod timeDuration = TimePeriod.between(date, date); - List contactEvents = fetchStaticEventsBetween(timeDuration); + List contactEvents = staticEventsProvider.fetchEventsBetween(timeDuration); if (namedayPreferences.isEnabled()) { List namedaysContactEvents = peopleNamedaysCalculator.loadSpecialNamedaysBetween(timeDuration); @@ -95,8 +73,7 @@ public List getCelebrationDateOn(Date date) { } public List getContactEventsFor(TimePeriod timeDuration) { - // todo this one - List contactEvents = fetchStaticEventsBetween(timeDuration); + List contactEvents = staticEventsProvider.fetchEventsBetween(timeDuration); if (namedayPreferences.isEnabled()) { List namedaysContactEvents = peopleNamedaysCalculator.loadSpecialNamedaysBetween(timeDuration); @@ -105,90 +82,10 @@ public List getContactEventsFor(TimePeriod timeDuration) { return Collections.unmodifiableList(contactEvents); } - private List fetchStaticEventsBetween(TimePeriod timeDuration) { - List contactEvents = new ArrayList<>(); - Cursor cursor = queryEventsFor(timeDuration); - throwIfInvalid(cursor); - while (cursor.moveToNext()) { - try { - ContactEvent contactEvent = getContactEventFrom(cursor); - contactEvents.add(contactEvent); - } catch (ContactNotFoundException e) { - Log.w(e); - } - } - cursor.close(); - return contactEvents; - } - - private Cursor queryEventsFor(TimePeriod timeDuration) { - if (isWithinTheSameYear(timeDuration)) { - return queryPeopleEvents(timeDuration, PeopleEvents.DATE + " ASC"); - } else { - return queryForBothYearsIn(timeDuration); - } - } - - private Cursor queryPeopleEvents(TimePeriod timePeriod, String sortOrder) { - String[] selectArgs = new String[]{ - SQLArgumentBuilder.dateWithoutYear(timePeriod.getStartingDate()), - SQLArgumentBuilder.dateWithoutYear(timePeriod.getEndingDate()), - }; - - Cursor cursor = resolver.query( - PeopleEvents.CONTENT_URI, - PROJECTION, - DATE_BETWEEN_IGNORING_YEAR, - selectArgs, - sortOrder - ); - if (isInvalid(cursor)) { - ErrorTracker.track(new IllegalStateException("People Events returned invalid cursor")); - } - return cursor; - } - - private Cursor queryForBothYearsIn(TimePeriod timeDuration) { - TimePeriod firstHalf = firstHalfOf(timeDuration); - Cursor[] cursors = new Cursor[2]; - cursors[0] = queryPeopleEvents(firstHalf, PeopleEvents.DATE + " ASC"); - TimePeriod secondHalf = secondHalfOf(timeDuration); - cursors[1] = queryPeopleEvents(secondHalf, PeopleEvents.DATE + " ASC"); - return new MergeCursor(cursors); - } - - private static TimePeriod firstHalfOf(TimePeriod timeDuration) { - return TimePeriod.between( - timeDuration.getStartingDate(), - Date.endOfYear(timeDuration.getStartingDate().getYear()) - ); - } - - private static TimePeriod secondHalfOf(TimePeriod timeDuration) { - return TimePeriod.between( - Date.startOfTheYear(timeDuration.getEndingDate().getYear()), - timeDuration.getEndingDate() - ); - } - - private boolean isWithinTheSameYear(TimePeriod timeDuration) { - return timeDuration.getStartingDate().getYear() == timeDuration.getEndingDate().getYear(); - } - - private ContactEvent getContactEventFrom(Cursor cursor) throws ContactNotFoundException { - long contactId = getContactIdFrom(cursor); - Contact contact = contactsProvider.getOrCreateContact(contactId); - Date date = getDateFrom(cursor); - EventType eventType = getEventType(cursor); - - Optional eventId = getDeviceEventIdFrom(cursor); - return new ContactEvent(eventId, eventType, date, contact); - } - public ContactEventsOnADate getCelebrationsClosestTo(Date date) { - Optional closestStaticDate = findClosestStaticEventDateFrom(date); - ContactEventsOnADate staticEvents = getStaticContactEventsFor(closestStaticDate.get()); - ContactEventsOnADate dynamicEvents = getDyanmicEvents(date, closestStaticDate); + Optional closestStaticDate = staticEventsProvider.findClosestStaticEventDateFrom(date); + ContactEventsOnADate staticEvents = staticEventsProvider.fetchEventsOn(date); + ContactEventsOnADate dynamicEvents = getDynamicEvents(date, closestStaticDate); if (DateComparator.INSTANCE.compare(closestStaticDate.get(), dynamicEvents.getDate()) == 0) { return ContactEventsOnADate.createFrom(dynamicEvents.getDate(), combine(dynamicEvents.getEvents(), staticEvents.getEvents())); @@ -199,7 +96,7 @@ public ContactEventsOnADate getCelebrationsClosestTo(Date date) { } } - private ContactEventsOnADate getDyanmicEvents(Date date, Optional closestStaticDate) { + private ContactEventsOnADate getDynamicEvents(Date date, Optional closestStaticDate) { if (namedayPreferences.isEnabled()) { Optional closestDynamicDate = findClosestDynamicEventDateTo(date); if (closestDynamicDate.isPresent()) { @@ -210,19 +107,6 @@ private ContactEventsOnADate getDyanmicEvents(Date date, Optional closestS return ContactEventsOnADate.createFrom(closestStaticDate.get(), Collections.emptyList()); } - private Optional findClosestStaticEventDateFrom(Date date) { - Cursor cursor = queryDateClosestTo(date); - try { - if (cursor.moveToFirst()) { - Date closestDate = getDateFrom(cursor); - return new Optional<>(closestDate); - } - return Optional.absent(); - } finally { - cursor.close(); - } - } - private Optional findClosestDynamicEventDateTo(Date date) { List contactEvents = peopleNamedaysCalculator.loadSpecialNamedaysBetween(TimePeriod.between(date, date.addWeek(4))); if (contactEvents.size() > 0) { @@ -231,99 +115,6 @@ private Optional findClosestDynamicEventDateTo(Date date) { return Optional.absent(); } - private ContactEventsOnADate getStaticContactEventsFor(Date date) { - List contactEvents = new ArrayList<>(); - Cursor cursor = resolver.query( - PeopleEvents.CONTENT_URI, - null, - PeopleEvents.DATE + " = ?", - getSelectArgs(date), - PeopleEvents.CONTACT_ID - ); - - while (cursor.moveToNext()) { - long contactId = getContactIdFrom(cursor); - try { - Contact contact = contactsProvider.getOrCreateContact(contactId); - EventType eventType = getEventType(cursor); - Optional deviceEventId = getDeviceEventIdFrom(cursor); - - ContactEvent event = new ContactEvent(deviceEventId, eventType, date, contact); - contactEvents.add(event); - } catch (Exception e) { - ErrorTracker.track(e); - } - } - cursor.close(); - return ContactEventsOnADate.createFrom(date, contactEvents); - } - - private static final Uri PEOPLE_EVENTS = PeopleEvents.CONTENT_URI; - - private Cursor queryDateClosestTo(Date date) { - // select * from annual_events WHERE substr(date,3) >= '03-04' ORDER BY substr(date,3) asc LIMIT 1 - return resolver.query( - PEOPLE_EVENTS, - PEOPLE_PROJECTION, - substr(PeopleEvents.DATE) + " >= ?", - monthAndDayOf(date), - substr(PeopleEvents.DATE) + " ASC LIMIT 1" - ); - } - - @NonNull - private String substr(String datetete) { - return "substr(" + datetete + ",3) "; - } - - private String[] monthAndDayOf(Date date) { - return new String[]{ - DateDisplayStringCreator.INSTANCE.stringOfNoYear(date) - }; - } - - private String[] getSelectArgs(Date date) { - return new String[]{date.toShortDate()}; - } - - private static void throwIfInvalid(Cursor cursor) { - if (isInvalid(cursor)) { - throw new RuntimeException("Invalid cursor"); - } - } - - private static boolean isInvalid(Cursor cursor) { - return cursor == null || cursor.isClosed(); - } - - private static Date getDateFrom(Cursor cursor) { - int index = cursor.getColumnIndexOrThrow(PeopleEventsContract.PeopleEvents.DATE); - String text = cursor.getString(index); - return from(text); - } - - private static long getContactIdFrom(Cursor cursor) { - int contactIdIndex = cursor.getColumnIndexOrThrow(PeopleEvents.CONTACT_ID); - return cursor.getLong(contactIdIndex); - } - - private EventType getEventType(Cursor cursor) { - int eventTypeIndex = cursor.getColumnIndexOrThrow(PeopleEvents.EVENT_TYPE); - @EventTypeId int rawEventType = cursor.getInt(eventTypeIndex); - if (rawEventType == EventColumns.TYPE_CUSTOM) { - Optional deviceEventIdFrom = getDeviceEventIdFrom(cursor); - if (deviceEventIdFrom.isPresent()) { - return queryCustomEvent(deviceEventIdFrom.get()); - } - return StandardEventType.OTHER; - } - return StandardEventType.fromId(rawEventType); - } - - private EventType queryCustomEvent(long deviceId) { - return customEventProvider.getEventWithId(deviceId); - } - private static Date from(String text) { try { return DateParser.INSTANCE.parse(text); @@ -333,19 +124,6 @@ private static Date from(String text) { } } - private static Optional getDeviceEventIdFrom(Cursor cursor) { - int eventId = cursor.getColumnIndexOrThrow(PeopleEvents.DEVICE_EVENT_ID); - long deviceEventId = cursor.getLong(eventId); - if (isALegitEventId(deviceEventId)) { - return Optional.absent(); - } - return new Optional<>(deviceEventId); - } - - private static boolean isALegitEventId(long deviceEventId) { - return deviceEventId == -1; - } - private static List combine(List listA, List listB) { List contactEvents = new ArrayList<>(); contactEvents.addAll(listA); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java new file mode 100644 index 00000000..ef03db3a --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java @@ -0,0 +1,207 @@ +package com.alexstyl.specialdates.service; + +import android.content.ContentResolver; +import android.database.Cursor; +import android.database.MergeCursor; +import android.net.Uri; + +import com.alexstyl.specialdates.Optional; +import com.alexstyl.specialdates.SQLArgumentBuilder; +import com.alexstyl.specialdates.contact.Contact; +import com.alexstyl.specialdates.contact.ContactNotFoundException; +import com.alexstyl.specialdates.contact.ContactsProvider; +import com.alexstyl.specialdates.date.ContactEvent; +import com.alexstyl.specialdates.date.Date; +import com.alexstyl.specialdates.date.DateDisplayStringCreator; +import com.alexstyl.specialdates.date.TimePeriod; +import com.alexstyl.specialdates.events.database.EventColumns; +import com.alexstyl.specialdates.events.database.EventTypeId; +import com.alexstyl.specialdates.events.database.PeopleEventsContract; +import com.alexstyl.specialdates.events.peopleevents.ContactEventsOnADate; +import com.alexstyl.specialdates.events.peopleevents.EventType; +import com.alexstyl.specialdates.events.peopleevents.StandardEventType; +import com.novoda.notils.logger.simple.Log; + +import java.util.ArrayList; +import java.util.List; + +import static com.novoda.notils.caster.Classes.from; + +class StaticPeopleEventsProvider { + + private static final String DATE_FROM = "substr(" + PeopleEventsContract.PeopleEvents.DATE + ",-5) >= ?"; + private static final String DATE_TO = "substr(" + PeopleEventsContract.PeopleEvents.DATE + ",-5) <= ?"; + private static final String DATE_BETWEEN_IGNORING_YEAR = DATE_FROM + " AND " + DATE_TO; + private static final String[] PEOPLE_PROJECTION = new String[]{PeopleEventsContract.PeopleEvents.DATE}; + private static final Uri PEOPLE_EVENTS = PeopleEventsContract.PeopleEvents.CONTENT_URI; + private static final String[] PROJECTION = { + PeopleEventsContract.PeopleEvents.CONTACT_ID, + PeopleEventsContract.PeopleEvents.DEVICE_EVENT_ID, + PeopleEventsContract.PeopleEvents.DATE, + PeopleEventsContract.PeopleEvents.EVENT_TYPE, + }; + + private final ContentResolver resolver; + private final ContactsProvider contactsProvider; + private final CustomEventProvider customEventProvider; + + StaticPeopleEventsProvider(ContentResolver resolver, ContactsProvider contactsProvider, CustomEventProvider customEventProvider) { + this.resolver = resolver; + this.contactsProvider = contactsProvider; + this.customEventProvider = customEventProvider; + } + + ContactEventsOnADate fetchEventsOn(Date date) { + return ContactEventsOnADate.createFrom(date, fetchEventsBetween(TimePeriod.between(date, date))); + } + + List fetchEventsBetween(TimePeriod timeDuration) { + List contactEvents = new ArrayList<>(); + Cursor cursor = queryEventsFor(timeDuration); + while (cursor.moveToNext()) { + try { + ContactEvent contactEvent = getContactEventFrom(cursor); + contactEvents.add(contactEvent); + } catch (ContactNotFoundException e) { + Log.w(e); + } + } + cursor.close(); + return contactEvents; + } + + private Cursor queryEventsFor(TimePeriod timeDuration) { + if (isWithinTheSameYear(timeDuration)) { + return queryPeopleEvents(timeDuration, PeopleEventsContract.PeopleEvents.DATE + " ASC"); + } else { + return queryForBothYearsIn(timeDuration); + } + } + + private Cursor queryPeopleEvents(TimePeriod timePeriod, String sortOrder) { + String[] selectArgs = new String[]{ + SQLArgumentBuilder.dateWithoutYear(timePeriod.getStartingDate()), + SQLArgumentBuilder.dateWithoutYear(timePeriod.getEndingDate()), + }; + + return resolver.query( + PeopleEventsContract.PeopleEvents.CONTENT_URI, + PROJECTION, + DATE_BETWEEN_IGNORING_YEAR, + selectArgs, + sortOrder + ); + } + + private Cursor queryForBothYearsIn(TimePeriod timeDuration) { + TimePeriod firstHalf = firstHalfOf(timeDuration); + Cursor[] cursors = new Cursor[2]; + cursors[0] = queryPeopleEvents(firstHalf, PeopleEventsContract.PeopleEvents.DATE + " ASC"); + TimePeriod secondHalf = secondHalfOf(timeDuration); + cursors[1] = queryPeopleEvents(secondHalf, PeopleEventsContract.PeopleEvents.DATE + " ASC"); + return new MergeCursor(cursors); + } + + private static TimePeriod firstHalfOf(TimePeriod timeDuration) { + return TimePeriod.between( + timeDuration.getStartingDate(), + Date.endOfYear(timeDuration.getStartingDate().getYear()) + ); + } + + private static TimePeriod secondHalfOf(TimePeriod timeDuration) { + return TimePeriod.between( + Date.startOfTheYear(timeDuration.getEndingDate().getYear()), + timeDuration.getEndingDate() + ); + } + + private boolean isWithinTheSameYear(TimePeriod timeDuration) { + return timeDuration.getStartingDate().getYear() == timeDuration.getEndingDate().getYear(); + } + + Optional findClosestStaticEventDateFrom(Date date) { + Cursor cursor = queryDateClosestTo(date); + try { + if (cursor.moveToFirst()) { + Date closestDate = getDateFrom(cursor); + return new Optional<>(closestDate); + } + return Optional.absent(); + } finally { + cursor.close(); + } + } + + private Cursor queryDateClosestTo(Date date) { + // select * from annual_events WHERE substr(date,3) >= '03-04' ORDER BY substr(date,3) asc LIMIT 1 + return resolver.query( + PEOPLE_EVENTS, + PEOPLE_PROJECTION, + substr(PeopleEventsContract.PeopleEvents.DATE) + " >= ?", + monthAndDayOf(date), + substr(PeopleEventsContract.PeopleEvents.DATE) + " ASC LIMIT 1" + ); + } + + private String substr(String datetete) { + return "substr(" + datetete + ",3) "; + } + + private String[] monthAndDayOf(Date date) { + return new String[]{ + DateDisplayStringCreator.INSTANCE.stringOfNoYear(date) + }; + } + + private static Date getDateFrom(Cursor cursor) { + int index = cursor.getColumnIndexOrThrow(PeopleEventsContract.PeopleEvents.DATE); + String text = cursor.getString(index); + return from(text); + } + + private static long getContactIdFrom(Cursor cursor) { + int contactIdIndex = cursor.getColumnIndexOrThrow(PeopleEventsContract.PeopleEvents.CONTACT_ID); + return cursor.getLong(contactIdIndex); + } + + private EventType getEventType(Cursor cursor) { + int eventTypeIndex = cursor.getColumnIndexOrThrow(PeopleEventsContract.PeopleEvents.EVENT_TYPE); + @EventTypeId int rawEventType = cursor.getInt(eventTypeIndex); + if (rawEventType == EventColumns.TYPE_CUSTOM) { + Optional deviceEventIdFrom = getDeviceEventIdFrom(cursor); + if (deviceEventIdFrom.isPresent()) { + return queryCustomEvent(deviceEventIdFrom.get()); + } + return StandardEventType.OTHER; + } + return StandardEventType.fromId(rawEventType); + } + + private ContactEvent getContactEventFrom(Cursor cursor) throws ContactNotFoundException { + long contactId = getContactIdFrom(cursor); + Contact contact = contactsProvider.getOrCreateContact(contactId); + Date date = getDateFrom(cursor); + EventType eventType = getEventType(cursor); + + Optional eventId = getDeviceEventIdFrom(cursor); + return new ContactEvent(eventId, eventType, date, contact); + } + + private static Optional getDeviceEventIdFrom(Cursor cursor) { + int eventId = cursor.getColumnIndexOrThrow(PeopleEventsContract.PeopleEvents.DEVICE_EVENT_ID); + long deviceEventId = cursor.getLong(eventId); + if (isALegitEventId(deviceEventId)) { + return Optional.absent(); + } + return new Optional<>(deviceEventId); + } + + private static boolean isALegitEventId(long deviceEventId) { + return deviceEventId == -1; + } + + private EventType queryCustomEvent(long deviceId) { + return customEventProvider.getEventWithId(deviceId); + } +} diff --git a/mobile/src/test/java/com/alexstyl/specialdates/ContactEventFixture.java b/mobile/src/test/java/com/alexstyl/specialdates/ContactEventFixture.java new file mode 100644 index 00000000..696cc5c5 --- /dev/null +++ b/mobile/src/test/java/com/alexstyl/specialdates/ContactEventFixture.java @@ -0,0 +1,30 @@ +package com.alexstyl.specialdates; + +import com.alexstyl.specialdates.contact.Contact; +import com.alexstyl.specialdates.date.ContactEvent; +import com.alexstyl.specialdates.date.Date; +import com.alexstyl.specialdates.events.peopleevents.EventType; + +import static com.alexstyl.specialdates.events.peopleevents.StandardEventType.*; + +public class ContactEventFixture { + + private static final Optional NO_DEVICE_CONTACT_ID = Optional.absent(); + + public ContactEvent aBirthdayFor(Contact contact, Date date) { + return anEventFor(contact, BIRTHDAY, date); + } + + public ContactEvent anAnniversaryFor(Contact contact, Date date) { + return anEventFor(contact, ANNIVERSARY, date); + } + + public ContactEvent aNamedayFor(Contact contact, Date date) { + return anEventFor(contact, NAMEDAY, date); + } + + private ContactEvent anEventFor(Contact contact, EventType eventType, Date date) { + return new ContactEvent(NO_DEVICE_CONTACT_ID, eventType, date, contact); + } + +} diff --git a/mobile/src/test/java/com/alexstyl/specialdates/TestContactEventBuilder.java b/mobile/src/test/java/com/alexstyl/specialdates/TestContactEventsBuilder.java similarity index 82% rename from mobile/src/test/java/com/alexstyl/specialdates/TestContactEventBuilder.java rename to mobile/src/test/java/com/alexstyl/specialdates/TestContactEventsBuilder.java index 3a47786d..a4ade6d2 100644 --- a/mobile/src/test/java/com/alexstyl/specialdates/TestContactEventBuilder.java +++ b/mobile/src/test/java/com/alexstyl/specialdates/TestContactEventsBuilder.java @@ -13,22 +13,22 @@ import static com.alexstyl.specialdates.events.peopleevents.StandardEventType.BIRTHDAY; import static com.alexstyl.specialdates.events.peopleevents.StandardEventType.NAMEDAY; -public class TestContactEventBuilder { +public class TestContactEventsBuilder { private static final Optional NO_DEVICE_CONTACT_ID = Optional.absent(); private List contactEvents = new ArrayList<>(); - public TestContactEventBuilder addBirthdayFor(Contact contact, Date date) { + public TestContactEventsBuilder addBirthdayFor(Contact contact, Date date) { addEventFor(contact, BIRTHDAY, date); return this; } - public TestContactEventBuilder addAnniversaryFor(Contact contact, Date date) { + public TestContactEventsBuilder addAnniversaryFor(Contact contact, Date date) { addEventFor(contact, ANNIVERSARY, date); return this; } - public TestContactEventBuilder addNamedayFor(Contact contact, Date date) { + public TestContactEventsBuilder addNamedayFor(Contact contact, Date date) { addEventFor(contact, NAMEDAY, date); return this; } diff --git a/mobile/src/test/java/com/alexstyl/specialdates/search/PeopleEventsSearchTest.java b/mobile/src/test/java/com/alexstyl/specialdates/search/PeopleEventsSearchTest.java index 392eb7c6..2ab886bd 100644 --- a/mobile/src/test/java/com/alexstyl/specialdates/search/PeopleEventsSearchTest.java +++ b/mobile/src/test/java/com/alexstyl/specialdates/search/PeopleEventsSearchTest.java @@ -2,7 +2,7 @@ import com.alexstyl.specialdates.DisplayName; import com.alexstyl.specialdates.TestContact; -import com.alexstyl.specialdates.TestContactEventBuilder; +import com.alexstyl.specialdates.TestContactEventsBuilder; import com.alexstyl.specialdates.contact.Contact; import com.alexstyl.specialdates.date.ContactEvent; import com.alexstyl.specialdates.date.Date; @@ -37,7 +37,7 @@ public class PeopleEventsSearchTest { @Before public void setUp() { search = new PeopleEventsSearch(mockProvider, NameMatcher.INSTANCE); - List contactEvents = new TestContactEventBuilder() + List contactEvents = new TestContactEventsBuilder() .addBirthdayFor(ALEX, JANUARY_1st) .addAnniversaryFor(MARIA, JANUARY_1st) .addNamedayFor(MIMOZA, JANUARY_1st) diff --git a/mobile/src/test/java/com/alexstyl/specialdates/service/PeopleEventsProviderTest.java b/mobile/src/test/java/com/alexstyl/specialdates/service/PeopleEventsProviderTest.java new file mode 100644 index 00000000..482bdd92 --- /dev/null +++ b/mobile/src/test/java/com/alexstyl/specialdates/service/PeopleEventsProviderTest.java @@ -0,0 +1,70 @@ +package com.alexstyl.specialdates.service; + +import com.alexstyl.specialdates.DisplayName; +import com.alexstyl.specialdates.TestContact; +import com.alexstyl.specialdates.TestContactEventsBuilder; +import com.alexstyl.specialdates.contact.Contact; +import com.alexstyl.specialdates.contact.ContactsProvider; +import com.alexstyl.specialdates.date.ContactEvent; +import com.alexstyl.specialdates.date.Date; +import com.alexstyl.specialdates.date.DateConstants; +import com.alexstyl.specialdates.date.TimePeriod; +import com.alexstyl.specialdates.events.namedays.NamedayPreferences; +import com.alexstyl.specialdates.events.namedays.calendar.resource.NamedayCalendarProvider; +import com.alexstyl.specialdates.events.peopleevents.PeopleNamedaysCalculator; +import com.novoda.notils.logger.simple.Log; + +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.fest.assertions.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class PeopleEventsProviderTest { + + private static final Contact PETER = new TestContact(1, DisplayName.from("Peter")); + + @Mock + private ContactsProvider mockContactsProvider; + @Mock + private NamedayPreferences mockNamedaysPreferences; + @Mock + private CustomEventProvider customEventProvider; + @Mock + private StaticPeopleEventsProvider mockStaticEventProvider; + + private PeopleEventsProvider peopleEventsProvider; + + @Before + public void setUp() { + Log.setShowLogs(false); + peopleEventsProvider = new PeopleEventsProvider( + mockContactsProvider, + mockNamedaysPreferences, + new PeopleNamedaysCalculator( + mockNamedaysPreferences, + mock(NamedayCalendarProvider.class), + mockContactsProvider + ), + mockStaticEventProvider + ); + } + + @Test + public void staticEventsAreReturnedCorrectly() { + Date date = Date.on(1, DateConstants.JANUARY, 2017); + List staticEvents = new TestContactEventsBuilder().addAnniversaryFor(PETER, date).build(); + + when(mockStaticEventProvider.fetchEventsBetween(TimePeriod.between(date, date))).thenReturn(staticEvents); + + List events = peopleEventsProvider.getCelebrationDateOn(date); + assertThat(events).containsOnly(staticEvents.get(0)); + } +} From 3a4ef2a2dabb79c51f43b1c16ff507ca9f37daca Mon Sep 17 00:00:00 2001 From: Alex Styl Date: Wed, 8 Mar 2017 21:59:41 +0000 Subject: [PATCH 4/7] Cover all test cases of PeoplEventsProvider --- .../PeopleNamedaysCalculator.java | 6 ++- .../service/PeopleEventsProvider.java | 4 +- .../service/StaticPeopleEventsProvider.java | 3 +- .../service/PeopleEventsProviderTest.java | 43 +++++++++++++++---- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java b/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java index e724eef1..a9694dcf 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/events/peopleevents/PeopleNamedaysCalculator.java @@ -14,12 +14,14 @@ import com.alexstyl.specialdates.events.namedays.calendar.resource.NamedayCalendarProvider; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; -public final class PeopleNamedaysCalculator { +public class PeopleNamedaysCalculator { private static final Optional NO_DEVICE_EVENT_ID = Optional.absent(); + private final NamedayPreferences namedayPreferences; private final NamedayCalendarProvider namedayCalendarProvider; private final ContactsProvider contactsProvider; @@ -84,7 +86,7 @@ public List loadSpecialNamedaysBetween(TimePeriod timeDuration) { } } } - return namedayEvents; + return Collections.unmodifiableList(namedayEvents); } private NameCelebrations getNamedaysOf(String given) { diff --git a/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java index 3ee08324..590301ab 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java @@ -62,8 +62,8 @@ public static PeopleEventsProvider newInstance(Context context) { public List getCelebrationDateOn(Date date) { TimePeriod timeDuration = TimePeriod.between(date, date); - List contactEvents = staticEventsProvider.fetchEventsBetween(timeDuration); - + List contactEvents = new ArrayList<>(); + contactEvents.addAll(staticEventsProvider.fetchEventsBetween(timeDuration)); if (namedayPreferences.isEnabled()) { List namedaysContactEvents = peopleNamedaysCalculator.loadSpecialNamedaysBetween(timeDuration); contactEvents.addAll(namedaysContactEvents); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java index ef03db3a..41ff01ed 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java @@ -23,6 +23,7 @@ import com.novoda.notils.logger.simple.Log; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static com.novoda.notils.caster.Classes.from; @@ -67,7 +68,7 @@ List fetchEventsBetween(TimePeriod timeDuration) { } } cursor.close(); - return contactEvents; + return Collections.unmodifiableList(contactEvents); } private Cursor queryEventsFor(TimePeriod timeDuration) { diff --git a/mobile/src/test/java/com/alexstyl/specialdates/service/PeopleEventsProviderTest.java b/mobile/src/test/java/com/alexstyl/specialdates/service/PeopleEventsProviderTest.java index 482bdd92..1a51ebf2 100644 --- a/mobile/src/test/java/com/alexstyl/specialdates/service/PeopleEventsProviderTest.java +++ b/mobile/src/test/java/com/alexstyl/specialdates/service/PeopleEventsProviderTest.java @@ -23,7 +23,6 @@ import org.mockito.runners.MockitoJUnitRunner; import static org.fest.assertions.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) @@ -39,6 +38,10 @@ public class PeopleEventsProviderTest { private CustomEventProvider customEventProvider; @Mock private StaticPeopleEventsProvider mockStaticEventProvider; + @Mock + private NamedayCalendarProvider mockNamedayCalendarProvider; + @Mock + private PeopleNamedaysCalculator mockPeopleNamedaysCalculator; private PeopleEventsProvider peopleEventsProvider; @@ -48,11 +51,7 @@ public void setUp() { peopleEventsProvider = new PeopleEventsProvider( mockContactsProvider, mockNamedaysPreferences, - new PeopleNamedaysCalculator( - mockNamedaysPreferences, - mock(NamedayCalendarProvider.class), - mockContactsProvider - ), + mockPeopleNamedaysCalculator, mockStaticEventProvider ); } @@ -60,11 +59,37 @@ public void setUp() { @Test public void staticEventsAreReturnedCorrectly() { Date date = Date.on(1, DateConstants.JANUARY, 2017); - List staticEvents = new TestContactEventsBuilder().addAnniversaryFor(PETER, date).build(); + List expectedEvents = new TestContactEventsBuilder().addAnniversaryFor(PETER, date).build(); + + when(mockStaticEventProvider.fetchEventsBetween(TimePeriod.between(date, date))).thenReturn(expectedEvents); + + List events = peopleEventsProvider.getCelebrationDateOn(date); + assertThat(events).containsOnly(expectedEvents.get(0)); + } + + @Test + public void dynamicEventsAreReturnedCorrectly() { + Date date = Date.on(1, DateConstants.JANUARY, 2017); + List expectedEvents = new TestContactEventsBuilder().addNamedayFor(PETER, date).build(); + when(mockNamedaysPreferences.isEnabled()).thenReturn(true); + when(mockPeopleNamedaysCalculator.loadSpecialNamedaysBetween(TimePeriod.between(date, date))).thenReturn(expectedEvents); + + List events = peopleEventsProvider.getCelebrationDateOn(date); + assertThat(events).containsOnly(expectedEvents.get(0)); + } + + @Test + public void combinedEventsAreReturnedCorrectly() { + Date date = Date.on(1, DateConstants.JANUARY, 2017); + List expectedDynamicEvents = new TestContactEventsBuilder().addNamedayFor(PETER, date).build(); + List expectedStaticEvents = new TestContactEventsBuilder().addAnniversaryFor(PETER, date).build(); - when(mockStaticEventProvider.fetchEventsBetween(TimePeriod.between(date, date))).thenReturn(staticEvents); + when(mockNamedaysPreferences.isEnabled()).thenReturn(true); + when(mockPeopleNamedaysCalculator.loadSpecialNamedaysBetween(TimePeriod.between(date, date))).thenReturn(expectedDynamicEvents); + when(mockStaticEventProvider.fetchEventsBetween(TimePeriod.between(date, date))).thenReturn(expectedStaticEvents); List events = peopleEventsProvider.getCelebrationDateOn(date); - assertThat(events).containsOnly(staticEvents.get(0)); + assertThat(events).containsAll(expectedDynamicEvents); + assertThat(events).containsAll(expectedStaticEvents); } } From dbddfd93c8a4abb391648e4d4540d488a9fad49e Mon Sep 17 00:00:00 2001 From: Alex Styl Date: Wed, 8 Mar 2017 22:14:29 +0000 Subject: [PATCH 5/7] Use new ArrayList instead of using existing unmodifyable list --- .../alexstyl/specialdates/service/PeopleEventsProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java index 590301ab..21677835 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/service/PeopleEventsProvider.java @@ -73,7 +73,8 @@ public List getCelebrationDateOn(Date date) { } public List getContactEventsFor(TimePeriod timeDuration) { - List contactEvents = staticEventsProvider.fetchEventsBetween(timeDuration); + List contactEvents = new ArrayList<>(); + contactEvents.addAll(staticEventsProvider.fetchEventsBetween(timeDuration)); if (namedayPreferences.isEnabled()) { List namedaysContactEvents = peopleNamedaysCalculator.loadSpecialNamedaysBetween(timeDuration); From 03c0f836551840a1e1db338ea3bc5945d034ce90 Mon Sep 17 00:00:00 2001 From: Alex Styl Date: Wed, 8 Mar 2017 22:15:57 +0000 Subject: [PATCH 6/7] Use proper parsing of date --- .../service/StaticPeopleEventsProvider.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java b/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java index 41ff01ed..8e76f703 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/service/StaticPeopleEventsProvider.java @@ -13,6 +13,7 @@ import com.alexstyl.specialdates.date.ContactEvent; import com.alexstyl.specialdates.date.Date; import com.alexstyl.specialdates.date.DateDisplayStringCreator; +import com.alexstyl.specialdates.date.DateParseException; import com.alexstyl.specialdates.date.TimePeriod; import com.alexstyl.specialdates.events.database.EventColumns; import com.alexstyl.specialdates.events.database.EventTypeId; @@ -20,14 +21,14 @@ import com.alexstyl.specialdates.events.peopleevents.ContactEventsOnADate; import com.alexstyl.specialdates.events.peopleevents.EventType; import com.alexstyl.specialdates.events.peopleevents.StandardEventType; +import com.alexstyl.specialdates.util.DateParser; +import com.novoda.notils.exception.DeveloperError; import com.novoda.notils.logger.simple.Log; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import static com.novoda.notils.caster.Classes.from; - class StaticPeopleEventsProvider { private static final String DATE_FROM = "substr(" + PeopleEventsContract.PeopleEvents.DATE + ",-5) >= ?"; @@ -157,8 +158,13 @@ private String[] monthAndDayOf(Date date) { private static Date getDateFrom(Cursor cursor) { int index = cursor.getColumnIndexOrThrow(PeopleEventsContract.PeopleEvents.DATE); - String text = cursor.getString(index); - return from(text); + String rawDate = cursor.getString(index); + try { + return DateParser.INSTANCE.parse(rawDate); + } catch (DateParseException e) { + e.printStackTrace(); + throw new DeveloperError("Invalid date stored to database. [" + rawDate + "]"); + } } private static long getContactIdFrom(Cursor cursor) { From 9d3016441d719ed13673c8c292647aeeffa6d175 Mon Sep 17 00:00:00 2001 From: Alex Styl Date: Wed, 8 Mar 2017 22:34:35 +0000 Subject: [PATCH 7/7] Rename to fix issue with compilation --- ...holidayCardView.java => BankCardView.java} | 4 ++-- .../BankHolidayCardViewHolder.java | 21 ------------------- .../datedetails/BankViewHolder.java | 21 +++++++++++++++++++ .../datedetails/DateDetailsAdapter.java | 4 ++-- .../src/main/res/layout/card_bankholiday.xml | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) rename mobile/src/main/java/com/alexstyl/specialdates/datedetails/{BankholidayCardView.java => BankCardView.java} (82%) delete mode 100644 mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankHolidayCardViewHolder.java create mode 100644 mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankViewHolder.java diff --git a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankholidayCardView.java b/mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankCardView.java similarity index 82% rename from mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankholidayCardView.java rename to mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankCardView.java index 7b358e94..b605f28b 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankholidayCardView.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankCardView.java @@ -8,11 +8,11 @@ import com.alexstyl.specialdates.events.bankholidays.BankHoliday; import com.alexstyl.specialdates.ui.MementoCardView; -public class BankHolidayCardView extends MementoCardView { +public class BankCardView extends MementoCardView { private final TextView text; - public BankHolidayCardView(Context context, AttributeSet attrs) { + public BankCardView(Context context, AttributeSet attrs) { super(context, attrs); inflate(context, R.layout.merge_bankholidaycardview, this); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankHolidayCardViewHolder.java b/mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankHolidayCardViewHolder.java deleted file mode 100644 index 70466852..00000000 --- a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankHolidayCardViewHolder.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.alexstyl.specialdates.datedetails; - -import android.support.v7.widget.RecyclerView; -import android.view.View; - -import com.alexstyl.specialdates.events.bankholidays.BankHoliday; - -class BankHolidayCardViewHolder extends RecyclerView.ViewHolder { - - private final BankHolidayCardView bankHolidayCardView; - - BankHolidayCardViewHolder(View itemView) { - super(itemView); - bankHolidayCardView = (BankHolidayCardView) itemView; - } - - void bind(BankHoliday holiday) { - bankHolidayCardView.display(holiday); - } - -} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankViewHolder.java b/mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankViewHolder.java new file mode 100644 index 00000000..782ff9c3 --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/datedetails/BankViewHolder.java @@ -0,0 +1,21 @@ +package com.alexstyl.specialdates.datedetails; + +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import com.alexstyl.specialdates.events.bankholidays.BankHoliday; + +class BankViewHolder extends RecyclerView.ViewHolder { + + private final BankCardView bankCardView; + + BankViewHolder(View itemView) { + super(itemView); + bankCardView = (BankCardView) itemView; + } + + void bind(BankHoliday holiday) { + bankCardView.display(holiday); + } + +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/DateDetailsAdapter.java b/mobile/src/main/java/com/alexstyl/specialdates/datedetails/DateDetailsAdapter.java index e2a79ddf..15e62f00 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/DateDetailsAdapter.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/datedetails/DateDetailsAdapter.java @@ -174,7 +174,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType } if (viewType == VIEW_TYPE_BANKHOLIDAY) { View view = layoutInflater.inflate(R.layout.card_bankholiday, parent, false); - return new BankHolidayCardViewHolder(view); + return new BankViewHolder(view); } throw new DeveloperError("Invalid viewType " + viewType); } @@ -190,7 +190,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ContactEvent event = getEvent(position); ((DateDetailsViewHolder) holder).bind(event, dateToDisplay, contactCardListener); } else if (type == VIEW_TYPE_BANKHOLIDAY) { - ((BankHolidayCardViewHolder) holder).bind(bankholiday.get()); + ((BankViewHolder) holder).bind(bankholiday.get()); } else { throw new DeveloperError("Invalid type : " + type); } diff --git a/mobile/src/main/res/layout/card_bankholiday.xml b/mobile/src/main/res/layout/card_bankholiday.xml index 9aa93bda..95c60082 100644 --- a/mobile/src/main/res/layout/card_bankholiday.xml +++ b/mobile/src/main/res/layout/card_bankholiday.xml @@ -1,4 +1,4 @@ -