Skip to content

Commit

Permalink
Add support for per-widget settings (plusonelabs#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
jtsymon committed Jul 25, 2014
1 parent b7aaee2 commit dbafc83
Show file tree
Hide file tree
Showing 14 changed files with 149 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
Expand All @@ -13,10 +14,13 @@
import android.net.Uri;
import android.preference.PreferenceManager;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.widget.RemoteViews;

import com.plusonelabs.calendar.prefs.UniquePreferencesFragment;

import org.joda.time.DateTime;

import java.util.List;
Expand Down Expand Up @@ -44,20 +48,23 @@ public class EventAppWidgetProvider extends AppWidgetProvider {

@Override
public void onUpdate(Context baseContext, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
int themeId = getCurrentThemeId(baseContext, PREF_HEADER_THEME, PREF_HEADER_THEME_DEFAULT);
Context context = new ContextThemeWrapper(baseContext, themeId);
AlarmReceiver.scheduleAlarm(context);
for (int widgetId : appWidgetIds) {
int themeId = getCurrentThemeId(
baseContext, PREF_HEADER_THEME, PREF_HEADER_THEME_DEFAULT,
UniquePreferencesFragment.getPreferences(baseContext, widgetId)
);
Context context = new ContextThemeWrapper(baseContext, themeId);
AlarmReceiver.scheduleAlarm(context);
SharedPreferences prefs = UniquePreferencesFragment.getPreferences(context, widgetId);
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget);
configureBackground(context, rv);
configureActionBar(context, rv);
configureBackground(context, rv, prefs);
configureActionBar(context, rv, widgetId, prefs);
configureList(context, widgetId, rv);
appWidgetManager.updateAppWidget(widgetId, rv);
}
}

private void configureBackground(Context context, RemoteViews rv) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
private void configureBackground(Context context, RemoteViews rv, SharedPreferences prefs) {
if (prefs.getBoolean(PREF_SHOW_HEADER, true)) {
rv.setViewVisibility(R.id.action_bar, View.VISIBLE);
} else {
Expand All @@ -69,14 +76,17 @@ private void configureBackground(Context context, RemoteViews rv) {
setAlpha(rv, R.id.background_image, alpha(color));
}

private void configureActionBar(Context context, RemoteViews rv) {
private void configureActionBar(Context context, RemoteViews rv, int widgetId, SharedPreferences prefs) {
rv.setOnClickPendingIntent(R.id.calendar_current_date, createOpenCalendarPendingIntent(context));
String formattedDate = DateUtils.formatDateTime(context, System.currentTimeMillis(),
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY);
rv.setTextViewText(R.id.calendar_current_date, formattedDate.toUpperCase(Locale.getDefault()));
setTextColorFromAttr(context, rv, R.id.calendar_current_date, R.attr.header);
setActionIcons(context, rv);
setActionIcons(context, rv, prefs);
Intent startConfigIntent = new Intent(context, WidgetConfigurationActivity.class);
startConfigIntent.setData(ContentUris.withAppendedId(Uri.EMPTY, widgetId));
startConfigIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
startConfigIntent.putExtra(WidgetConfigurationActivity.WIDGET_INIT, false);
PendingIntent menuPendingIntent = PendingIntent.getActivity(context, 0, startConfigIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
rv.setOnClickPendingIntent(R.id.overflow_menu, menuPendingIntent);
Expand All @@ -90,10 +100,10 @@ private void configureActionBar(Context context, RemoteViews rv) {
}
}

private void setActionIcons(Context context, RemoteViews rv) {
private void setActionIcons(Context context, RemoteViews rv, SharedPreferences prefs) {
setImageFromAttr(context, rv, R.id.add_event, R.attr.header_action_add_event);
setImageFromAttr(context, rv, R.id.overflow_menu, R.attr.header_action_overflow);
int themeId = getCurrentThemeId(context, PREF_HEADER_THEME, PREF_HEADER_THEME_DEFAULT);
int themeId = getCurrentThemeId(context, PREF_HEADER_THEME, PREF_HEADER_THEME_DEFAULT, prefs);
int alpha = 255;
if (themeId == R.style.Theme_Calendar_Dark || themeId == R.style.Theme_Calendar_Light) {
alpha = 154;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.format.DateUtils;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService.RemoteViewsFactory;

import com.plusonelabs.calendar.calendar.CalendarEventVisualizer;
import com.plusonelabs.calendar.model.DayHeader;
import com.plusonelabs.calendar.model.Event;
import com.plusonelabs.calendar.prefs.UniquePreferencesFragment;

import org.joda.time.DateTime;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

Expand All @@ -37,11 +36,13 @@ public class EventRemoteViewsFactory implements RemoteViewsFactory {
private final Context context;
private final List<Event> eventEntries;
private final List<IEventVisualizer<?>> eventProviders;
private final SharedPreferences prefs;

public EventRemoteViewsFactory(Context context) {
public EventRemoteViewsFactory(Context context, SharedPreferences prefs) {
this.context = context;
this.prefs = prefs;
eventProviders = new ArrayList<>();
eventProviders.add(new CalendarEventVisualizer(context));
eventProviders.add(new CalendarEventVisualizer(context, prefs));
eventEntries = new ArrayList<>();
}

Expand Down Expand Up @@ -74,24 +75,23 @@ public RemoteViews getViewAt(int position) {
}

public RemoteViews updateDayHeader(DayHeader dayHeader) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String alignment = prefs.getString(PREF_DAY_HEADER_ALIGNMENT, PREF_DAY_HEADER_ALIGNMENT_DEFAULT);
RemoteViews rv = new RemoteViews(context.getPackageName(), valueOf(alignment).getLayoutId());
String dateString = DateUtil.createDateString(context, dayHeader.getStartDate())
.toUpperCase(Locale.getDefault());
rv.setTextViewText(R.id.day_header_title, dateString);
setTextSize(context, rv, R.id.day_header_title, R.dimen.day_header_title);
setTextSize(context, rv, R.id.day_header_title, R.dimen.day_header_title, prefs);
setTextColorFromAttr(context, rv, R.id.day_header_title, R.attr.dayHeaderTitle);
setBackgroundColorFromAttr(context, rv, R.id.day_header_separator, R.attr.dayHeaderSeparator);
setPadding(context, rv, R.id.day_header_title, 0, R.dimen.day_header_padding_top,
R.dimen.day_header_padding_right, R.dimen.day_header_padding_bottom);
R.dimen.day_header_padding_right, R.dimen.day_header_padding_bottom, prefs);
Intent intent = createOpenCalendarAtDayIntent(dayHeader.getStartDate());
rv.setOnClickFillInIntent(R.id.day_header, intent);
return rv;
}

public void onDataSetChanged() {
context.setTheme(getCurrentThemeId(context, PREF_ENTRY_THEME, PREF_ENTRY_THEME_DEFAULT));
context.setTheme(getCurrentThemeId(context, PREF_ENTRY_THEME, PREF_ENTRY_THEME_DEFAULT, prefs));
eventEntries.clear();
List<Event> events = new ArrayList<>();
for (IEventVisualizer<?> eventProvider : eventProviders) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.plusonelabs.calendar;

import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.widget.RemoteViewsService;

import com.plusonelabs.calendar.prefs.UniquePreferencesFragment;

import static com.plusonelabs.calendar.Theme.getCurrentThemeId;
import static com.plusonelabs.calendar.prefs.CalendarPreferences.PREF_ENTRY_THEME;
import static com.plusonelabs.calendar.prefs.CalendarPreferences.PREF_ENTRY_THEME_DEFAULT;
Expand All @@ -15,8 +20,11 @@ public class EventWidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
Context appContext = getApplicationContext();
int currentThemeId = getCurrentThemeId(appContext, PREF_ENTRY_THEME, PREF_ENTRY_THEME_DEFAULT);
Bundle extras = intent.getExtras();
int widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
SharedPreferences prefs = UniquePreferencesFragment.getPreferences(appContext, widgetId);
int currentThemeId = getCurrentThemeId(appContext, PREF_ENTRY_THEME, PREF_ENTRY_THEME_DEFAULT, prefs);
ContextThemeWrapper context = new ContextThemeWrapper(appContext, currentThemeId);
return new EventRemoteViewsFactory(context);
return new EventRemoteViewsFactory(context, prefs);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ private RemoteViewsUtil() {

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static void setPadding(Context context, RemoteViews rv, int viewId, int leftDimenId,
int topDimenId, int rightDimenId, int bottomDimenId) {
int topDimenId, int rightDimenId, int bottomDimenId, SharedPreferences prefs) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
int leftPadding = Math.round(getScaledValueInPixel(context, leftDimenId));
int topPadding = Math.round(getScaledValueInPixel(context, topDimenId));
int rightPadding = Math.round(getScaledValueInPixel(context, rightDimenId));
int bottomPadding = Math.round(getScaledValueInPixel(context, bottomDimenId));
int leftPadding = Math.round(getScaledValueInPixel(context, leftDimenId, prefs));
int topPadding = Math.round(getScaledValueInPixel(context, topDimenId, prefs));
int rightPadding = Math.round(getScaledValueInPixel(context, rightDimenId, prefs));
int bottomPadding = Math.round(getScaledValueInPixel(context, bottomDimenId, prefs));
rv.setViewPadding(viewId, leftPadding, topPadding, rightPadding, bottomPadding);
}
}
Expand All @@ -45,8 +45,8 @@ public static void setColorFilter(RemoteViews rv, int viewId, int color) {
rv.setInt(viewId, METHOD_SET_COLOR_FILTER, color);
}

public static void setTextSize(Context context, RemoteViews rv, int viewId, int dimenId) {
rv.setFloat(viewId, METHOD_SET_TEXT_SIZE, getScaledValue(context, dimenId));
public static void setTextSize(Context context, RemoteViews rv, int viewId, int dimenId, SharedPreferences prefs) {
rv.setFloat(viewId, METHOD_SET_TEXT_SIZE, getScaledValue(context, dimenId, prefs));
}

public static void setTextColorFromAttr(Context context, RemoteViews rv, int viewId, int colorAttrId) {
Expand All @@ -63,17 +63,15 @@ public static void setBackgroundColor(RemoteViews rv, int viewId, int color) {
}


private static float getScaledValueInPixel(Context context, int dimenId) {
private static float getScaledValueInPixel(Context context, int dimenId, SharedPreferences prefs) {
float resValue = getDimension(context, dimenId);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
float prefTextScale = parseFloat(prefs.getString(PREF_TEXT_SIZE_SCALE,
PREF_TEXT_SIZE_SCALE_DEFAULT));
return resValue * prefTextScale;
}

private static float getScaledValue(Context context, int dimenId) {
private static float getScaledValue(Context context, int dimenId, SharedPreferences prefs) {
float resValue = getDimension(context, dimenId);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
float density = context.getResources().getDisplayMetrics().density;
float prefTextScale = parseFloat(prefs.getString(PREF_TEXT_SIZE_SCALE,
PREF_TEXT_SIZE_SCALE_DEFAULT));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ private Theme(int themeResId) {
this.themeResId = themeResId;
}

public static int getCurrentThemeId(Context context, String prefKey, String prefDefault) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
public static int getCurrentThemeId(Context context, String prefKey, String prefDefault, SharedPreferences prefs) {
return Theme.valueOf(prefs.getString(prefKey, prefDefault)).themeResId;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;
Expand All @@ -19,22 +20,43 @@
public class WidgetConfigurationActivity extends PreferenceActivity {

private static final String PREFERENCES_PACKAGE_NAME = "com.plusonelabs.calendar.prefs";
public static final String WIDGET_INIT = "widgetInit";

private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
public int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
private boolean init = true;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if (extras != null) {
appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (savedInstanceState != null) {
appWidgetId = savedInstanceState.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
init = savedInstanceState.getBoolean(WidgetConfigurationActivity.WIDGET_INIT);
} else {
Bundle extras = getIntent().getExtras();
if (extras != null) {
appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
init = extras.getBoolean(WidgetConfigurationActivity.WIDGET_INIT, true);
}
}
if (hasHeaders() && appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
if (init && appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && hasHeaders()) {
createAddButton();
}
}

@Override
public Intent onBuildStartFragmentIntent (String fragmentName, Bundle args, int titleRes, int shortTitleRes) {
Intent intent = super.onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, this.appWidgetId);
return intent;
}

@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
outState.putBoolean(WidgetConfigurationActivity.WIDGET_INIT, init);
}

private void createAddButton() {
TypedValue value = new TypedValue();
getTheme().resolveAttribute(android.R.attr.dividerHorizontal, value, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ public class CalendarEventProvider {
private static final String AND_BRACKET = " AND (";

private final Context context;
private final SharedPreferences prefs;

public CalendarEventProvider(Context context) {
public CalendarEventProvider(Context context, SharedPreferences prefs) {
this.context = context;
this.prefs = prefs;
}

public List<CalendarEvent> getEvents() {
Expand All @@ -66,7 +68,6 @@ public List<CalendarEvent> getEvents() {
}

private List<CalendarEvent> createEventList(Cursor calendarCursor) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean fillAllDayEvents = prefs.getBoolean(PREF_FILL_ALL_DAY, PREF_FILL_ALL_DAY_DEFAULT);
List<CalendarEvent> eventList = new ArrayList<>();
for (int i = 0; i < calendarCursor.getCount(); i++) {
Expand Down Expand Up @@ -164,7 +165,6 @@ private int getAsOpaque(int color) {
}

private Cursor createLoadedCursor() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
int dateRange = Integer
.valueOf(prefs.getString(PREF_EVENT_RANGE, PREF_EVENT_RANGE_DEFAULT));
long start = System.currentTimeMillis();
Expand All @@ -185,7 +185,6 @@ private String[] getProjection() {
}

private String createSelectionClause() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Set<String> activeCalenders = prefs.getStringSet(CalendarPreferences.PREF_ACTIVE_CALENDARS,
new HashSet<String>());
if (activeCalenders.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.plusonelabs.calendar.IEventVisualizer;
import com.plusonelabs.calendar.R;
import com.plusonelabs.calendar.model.Event;
import com.plusonelabs.calendar.prefs.UniquePreferencesFragment;

import org.joda.time.DateTime;

Expand Down Expand Up @@ -55,10 +56,10 @@ public class CalendarEventVisualizer implements IEventVisualizer<CalendarEvent>
private final CalendarEventProvider calendarContentProvider;
private final SharedPreferences prefs;

public CalendarEventVisualizer(Context context) {
public CalendarEventVisualizer(Context context, SharedPreferences prefs) {
this.context = context;
calendarContentProvider = new CalendarEventProvider(context);
prefs = PreferenceManager.getDefaultSharedPreferences(context);
this.prefs = prefs;
calendarContentProvider = new CalendarEventProvider(context, prefs);
}

public RemoteViews getRemoteView(Event eventEntry) {
Expand All @@ -79,7 +80,7 @@ private void setTitle(CalendarEvent event, RemoteViews rv) {
title = context.getResources().getString(R.string.no_title);
}
rv.setTextViewText(R.id.event_entry_title, title);
setTextSize(context, rv, R.id.event_entry_title, R.dimen.event_entry_title);
setTextSize(context, rv, R.id.event_entry_title, R.dimen.event_entry_title, prefs);
setTextColorFromAttr(context, rv, R.id.event_entry_title, R.attr.eventEntryTitle);
setSingleLine(rv, R.id.event_entry_title,
!prefs.getBoolean(PREF_MULTILINE_TITLE, PREF_MULTILINE_TITLE_DEFAULT));
Expand All @@ -99,7 +100,7 @@ private void setEventDetails(CalendarEvent event, RemoteViews rv) {
}
rv.setViewVisibility(R.id.event_entry_details, View.VISIBLE);
rv.setTextViewText(R.id.event_entry_details, eventDetails);
setTextSize(context, rv, R.id.event_entry_details, R.dimen.event_entry_details);
setTextSize(context, rv, R.id.event_entry_details, R.dimen.event_entry_details, prefs);
setTextColorFromAttr(context, rv, R.id.event_entry_details, R.attr.eventEntryDetails);
}
}
Expand All @@ -118,7 +119,7 @@ private void setIndicator(RemoteViews rv, boolean showIndication, int viewId, in
if (showIndication) {
rv.setViewVisibility(viewId, View.VISIBLE);
setImageFromAttr(context, rv, viewId, imageAttrId);
int themeId = getCurrentThemeId(context, PREF_ENTRY_THEME, PREF_ENTRY_THEME_DEFAULT);
int themeId = getCurrentThemeId(context, PREF_ENTRY_THEME, PREF_ENTRY_THEME_DEFAULT, prefs);
int alpha = 255;
if (themeId == R.style.Theme_Calendar_Dark || themeId == R.style.Theme_Calendar_Light) {
alpha = 128;
Expand Down Expand Up @@ -178,7 +179,6 @@ private String createTimeStringForEventEntry(CalendarEvent event) {
}

private String createTimeString(DateTime time) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String dateFormat = prefs.getString(PREF_DATE_FORMAT, PREF_DATE_FORMAT_DEFAULT);
if (DateUtil.hasAmPmClock(Locale.getDefault()) && dateFormat.equals(AUTO)
|| dateFormat.equals(TWELVE)) {
Expand Down
Loading

6 comments on commit dbafc83

@jtsymon
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This just completely separates the settings for each instance of the widget.
It works, but its kind of messy (passing preference objects and widget ids all over the place)... Maybe someone with more experience with Android knows a way to tidy it up / do it better?

@jtsymon
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot of two instances of the widget showing different calendars (and with different colour settings as well):

Screenshot

@rICTx-T1D
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is it possible to download a apk-File for this commit???? When the branch is mergin n master-branch?

@jtsymon
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I installed it on my phone using debug mode.
I'll make a pull request, but I'm not sure it'll be accepted since the code's kind of a mess (which is why I hadn't made a pull request in the first place).

@mpost
Copy link

@mpost mpost commented on dbafc83 Sep 1, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the initial work. Looks very promising. As you pointed out, the code became quite tangled. We should think about a better way to isolate the different widgets. I'll get back to that asap.

@mpost
Copy link

@mpost mpost commented on dbafc83 Sep 14, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a small comment in the code. Could you also please rebase your PR? I have also commited an intellij formatter which you should use to bring your source formatting in line with the rest of the source base.

Regarding the change itself... As discussed before, passing the prefs and widgetId around is not really cool. I think we should consider using something like dagger to inject appropriately configured prefs. I will look into that soon.

Please sign in to comment.