mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
StackWidget: allow user to select habits
This commit is contained in:
@@ -30,21 +30,26 @@ import org.isoron.uhabits.*;
|
|||||||
import org.isoron.uhabits.core.preferences.*;
|
import org.isoron.uhabits.core.preferences.*;
|
||||||
import org.isoron.uhabits.intents.*;
|
import org.isoron.uhabits.intents.*;
|
||||||
|
|
||||||
import static android.view.View.MeasureSpec.*;
|
import static android.view.View.MeasureSpec.makeMeasureSpec;
|
||||||
|
|
||||||
public abstract class BaseWidget
|
public abstract class BaseWidget
|
||||||
{
|
{
|
||||||
private final WidgetPreferences prefs;
|
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private WidgetDimensions dimensions;
|
protected final WidgetPreferences widgetPrefs;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected final Preferences prefs;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected final PendingIntentFactory pendingIntentFactory;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
protected final PendingIntentFactory pendingIntentFactory;
|
@NonNull
|
||||||
|
private WidgetDimensions dimensions;
|
||||||
|
|
||||||
public BaseWidget(@NonNull Context context, int id)
|
public BaseWidget(@NonNull Context context, int id)
|
||||||
{
|
{
|
||||||
@@ -54,15 +59,16 @@ public abstract class BaseWidget
|
|||||||
HabitsApplication app =
|
HabitsApplication app =
|
||||||
(HabitsApplication) context.getApplicationContext();
|
(HabitsApplication) context.getApplicationContext();
|
||||||
|
|
||||||
prefs = app.getComponent().getWidgetPreferences();
|
widgetPrefs = app.getComponent().getWidgetPreferences();
|
||||||
|
prefs = app.getComponent().getPreferences();
|
||||||
pendingIntentFactory = app.getComponent().getPendingIntentFactory();
|
pendingIntentFactory = app.getComponent().getPendingIntentFactory();
|
||||||
dimensions = new WidgetDimensions(getDefaultWidth(), getDefaultHeight(),
|
dimensions = new WidgetDimensions(getDefaultWidth(), getDefaultHeight(),
|
||||||
getDefaultWidth(), getDefaultHeight());
|
getDefaultWidth(), getDefaultHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete()
|
public void delete()
|
||||||
{
|
{
|
||||||
prefs.removeWidget(id);
|
widgetPrefs.removeWidget(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -80,7 +86,7 @@ public abstract class BaseWidget
|
|||||||
public RemoteViews getLandscapeRemoteViews()
|
public RemoteViews getLandscapeRemoteViews()
|
||||||
{
|
{
|
||||||
return getRemoteViews(dimensions.getLandscapeWidth(),
|
return getRemoteViews(dimensions.getLandscapeWidth(),
|
||||||
dimensions.getLandscapeHeight());
|
dimensions.getLandscapeHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract PendingIntent getOnClickPendingIntent(Context context);
|
public abstract PendingIntent getOnClickPendingIntent(Context context);
|
||||||
@@ -89,7 +95,7 @@ public abstract class BaseWidget
|
|||||||
public RemoteViews getPortraitRemoteViews()
|
public RemoteViews getPortraitRemoteViews()
|
||||||
{
|
{
|
||||||
return getRemoteViews(dimensions.getPortraitWidth(),
|
return getRemoteViews(dimensions.getPortraitWidth(),
|
||||||
dimensions.getPortraitHeight());
|
dimensions.getPortraitHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void refreshData(View widgetView);
|
public abstract void refreshData(View widgetView);
|
||||||
@@ -139,7 +145,7 @@ public abstract class BaseWidget
|
|||||||
int w = (int) (((float) entireWidth - imageWidth) / 2);
|
int w = (int) (((float) entireWidth - imageWidth) / 2);
|
||||||
int h = (int) (((float) entireHeight - imageHeight) / 2);
|
int h = (int) (((float) entireHeight - imageHeight) / 2);
|
||||||
|
|
||||||
return new int[]{ w, h, w, h };
|
return new int[]{w, h, w, h};
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -183,7 +189,7 @@ public abstract class BaseWidget
|
|||||||
|
|
||||||
entireView.measure(specWidth, specHeight);
|
entireView.measure(specWidth, specHeight);
|
||||||
entireView.layout(0, 0, entireView.getMeasuredWidth(),
|
entireView.layout(0, 0, entireView.getMeasuredWidth(),
|
||||||
entireView.getMeasuredHeight());
|
entireView.getMeasuredHeight());
|
||||||
|
|
||||||
View imageView = entireView.findViewById(R.id.imageView);
|
View imageView = entireView.findViewById(R.id.imageView);
|
||||||
width = imageView.getMeasuredWidth();
|
width = imageView.getMeasuredWidth();
|
||||||
|
|||||||
@@ -19,26 +19,19 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.widgets;
|
package org.isoron.uhabits.widgets;
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.*;
|
||||||
import android.appwidget.AppWidgetProvider;
|
import android.content.*;
|
||||||
import android.content.Context;
|
import android.os.*;
|
||||||
import android.os.Bundle;
|
import android.support.annotation.*;
|
||||||
import android.os.Looper;
|
import android.widget.*;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.HabitsApplication;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.R;
|
import org.isoron.uhabits.core.models.*;
|
||||||
import org.isoron.uhabits.core.models.Habit;
|
import org.isoron.uhabits.core.preferences.*;
|
||||||
import org.isoron.uhabits.core.models.HabitList;
|
|
||||||
import org.isoron.uhabits.core.models.HabitNotFoundException;
|
|
||||||
import org.isoron.uhabits.core.preferences.WidgetPreferences;
|
|
||||||
|
|
||||||
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT;
|
import java.util.*;
|
||||||
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH;
|
|
||||||
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT;
|
import static android.appwidget.AppWidgetManager.*;
|
||||||
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH;
|
|
||||||
import static org.isoron.androidbase.utils.InterfaceUtils.dpToPixels;
|
import static org.isoron.androidbase.utils.InterfaceUtils.dpToPixels;
|
||||||
|
|
||||||
public abstract class BaseWidgetProvider extends AppWidgetProvider
|
public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||||
@@ -141,15 +134,18 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
|||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Habit getHabitFromWidgetId(int widgetId)
|
protected List<Habit> getHabitsFromWidgetId(int widgetId)
|
||||||
{
|
{
|
||||||
long habitId = widgetPrefs.getHabitIdFromWidgetId(widgetId);
|
long selectedIds[] = widgetPrefs.getHabitIdsFromWidgetId(widgetId);
|
||||||
if (habitId == WidgetPreferences.STACK_WIDGET_HABITS) {
|
ArrayList<Habit> selectedHabits = new ArrayList<>(selectedIds.length);
|
||||||
return null;
|
for (long id : selectedIds)
|
||||||
|
{
|
||||||
|
Habit h = habits.getById(id);
|
||||||
|
if (h == null) throw new HabitNotFoundException();
|
||||||
|
selectedHabits.add(h);
|
||||||
}
|
}
|
||||||
Habit habit = habits.getById(habitId);
|
|
||||||
if (habit == null) throw new HabitNotFoundException();
|
return selectedHabits;
|
||||||
return habit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|||||||
@@ -18,17 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.isoron.uhabits.widgets
|
package org.isoron.uhabits.widgets
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.*
|
||||||
|
|
||||||
class CheckmarkWidgetProvider : BaseWidgetProvider() {
|
class CheckmarkWidgetProvider : BaseWidgetProvider() {
|
||||||
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
||||||
// if the habit was null, but did not have a habit id associated with a stack widget,
|
val habits = getHabitsFromWidgetId(id)
|
||||||
// `getHabitFromWidgetId` will throw a HabitNotFoundException
|
if (habits.size == 1) return CheckmarkWidget(context, id, habits[0])
|
||||||
val habit = getHabitFromWidgetId(id)
|
else return StackWidget(context, id, StackWidgetType.CHECKMARK, habits)
|
||||||
if (habit != null) {
|
|
||||||
return CheckmarkWidget(context, id, habit)
|
|
||||||
} else {
|
|
||||||
return StackWidget(context, id, StackWidgetType.CHECKMARK)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,17 +19,12 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.widgets
|
package org.isoron.uhabits.widgets
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.*
|
||||||
|
|
||||||
class FrequencyWidgetProvider : BaseWidgetProvider() {
|
class FrequencyWidgetProvider : BaseWidgetProvider() {
|
||||||
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
||||||
// if the habit was null, but did not have a habit id associated with a stack widget,
|
val habits = getHabitsFromWidgetId(id)
|
||||||
// `getHabitFromWidgetId` will throw a HabitNotFoundException
|
if (habits.size == 1) return FrequencyWidget(context, id, habits[0])
|
||||||
val habit = getHabitFromWidgetId(id)
|
else return StackWidget(context, id, StackWidgetType.FREQUENCY, habits)
|
||||||
if (habit != null) {
|
|
||||||
return FrequencyWidget(context, id, habit)
|
|
||||||
} else {
|
|
||||||
return StackWidget(context, id, StackWidgetType.FREQUENCY)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,21 +23,21 @@ import android.app.*
|
|||||||
import android.appwidget.AppWidgetManager.*
|
import android.appwidget.AppWidgetManager.*
|
||||||
import android.content.*
|
import android.content.*
|
||||||
import android.os.*
|
import android.os.*
|
||||||
import android.util.Log
|
|
||||||
import android.view.*
|
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
|
import android.widget.AbsListView.*
|
||||||
import org.isoron.uhabits.*
|
import org.isoron.uhabits.*
|
||||||
import org.isoron.uhabits.core.models.*
|
import org.isoron.uhabits.core.models.*
|
||||||
import org.isoron.uhabits.core.preferences.*
|
import org.isoron.uhabits.core.preferences.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class HabitPickerDialog : Activity(), AdapterView.OnItemClickListener {
|
class HabitPickerDialog : Activity() {
|
||||||
|
|
||||||
private var widgetId = 0
|
private var widgetId = 0
|
||||||
private lateinit var habitList: HabitList
|
private lateinit var habitList: HabitList
|
||||||
private lateinit var preferences: WidgetPreferences
|
private lateinit var preferences: WidgetPreferences
|
||||||
private lateinit var habitIds: ArrayList<Long>
|
private lateinit var habitIds: ArrayList<Long>
|
||||||
private lateinit var widgetUpdater: WidgetUpdater
|
private lateinit var widgetUpdater: WidgetUpdater
|
||||||
|
private lateinit var listView: ListView
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -45,26 +45,35 @@ class HabitPickerDialog : Activity(), AdapterView.OnItemClickListener {
|
|||||||
habitList = component.habitList
|
habitList = component.habitList
|
||||||
preferences = component.widgetPreferences
|
preferences = component.widgetPreferences
|
||||||
widgetUpdater = component.widgetUpdater
|
widgetUpdater = component.widgetUpdater
|
||||||
widgetId = intent.extras?.getInt(EXTRA_APPWIDGET_ID,
|
widgetId = intent.extras?.getInt(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID) ?: 0
|
||||||
INVALID_APPWIDGET_ID) ?: 0
|
|
||||||
|
|
||||||
habitIds = ArrayList<Long>()
|
habitIds = ArrayList()
|
||||||
val habitNames = ArrayList<String>()
|
val habitNames = ArrayList<String>()
|
||||||
for (h in habitList) {
|
for (h in habitList) {
|
||||||
if (h.isArchived) continue
|
if (h.isArchived) continue
|
||||||
habitIds.add(h.getId()!!)
|
habitIds.add(h.id!!)
|
||||||
habitNames.add(h.name)
|
habitNames.add(h.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(R.layout.widget_configure_activity)
|
setContentView(R.layout.widget_configure_activity)
|
||||||
with(findViewById(R.id.listView) as ListView) {
|
listView = findViewById(R.id.listView) as ListView
|
||||||
adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1,
|
|
||||||
habitNames)
|
with(listView) {
|
||||||
onItemClickListener = this@HabitPickerDialog
|
adapter = ArrayAdapter(context, android.R.layout.simple_list_item_multiple_choice, habitNames)
|
||||||
|
choiceMode = CHOICE_MODE_MULTIPLE
|
||||||
|
itemsCanFocus = false
|
||||||
}
|
}
|
||||||
with(findViewById(R.id.createStackWidgetButton) as Button) {
|
|
||||||
setOnClickListener(View.OnClickListener {
|
with(findViewById(R.id.buttonSave) as Button) {
|
||||||
preferences.addWidget(widgetId, WidgetPreferences.STACK_WIDGET_HABITS)
|
setOnClickListener({
|
||||||
|
val selectedIds = mutableListOf<Long>()
|
||||||
|
for (i in 0..listView.count) {
|
||||||
|
if (listView.isItemChecked(i)) {
|
||||||
|
selectedIds.add(habitIds[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences.addWidget(widgetId, selectedIds.toLongArray())
|
||||||
widgetUpdater.updateWidgets()
|
widgetUpdater.updateWidgets()
|
||||||
setResult(Activity.RESULT_OK, Intent().apply {
|
setResult(Activity.RESULT_OK, Intent().apply {
|
||||||
putExtra(EXTRA_APPWIDGET_ID, widgetId)
|
putExtra(EXTRA_APPWIDGET_ID, widgetId)
|
||||||
@@ -73,16 +82,4 @@ class HabitPickerDialog : Activity(), AdapterView.OnItemClickListener {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemClick(parent: AdapterView<*>,
|
|
||||||
view: View,
|
|
||||||
position: Int,
|
|
||||||
id: Long) {
|
|
||||||
preferences.addWidget(widgetId, habitIds[position])
|
|
||||||
widgetUpdater.updateWidgets()
|
|
||||||
setResult(Activity.RESULT_OK, Intent().apply {
|
|
||||||
putExtra(EXTRA_APPWIDGET_ID, widgetId)
|
|
||||||
})
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.isoron.uhabits.widgets
|
package org.isoron.uhabits.widgets
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.*
|
||||||
|
|
||||||
class HistoryWidgetProvider : BaseWidgetProvider() {
|
class HistoryWidgetProvider : BaseWidgetProvider() {
|
||||||
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
||||||
// if the habit was null, but did not have a habit id associated with a stack widget,
|
val habits = getHabitsFromWidgetId(id)
|
||||||
// `getHabitFromWidgetId` will throw a HabitNotFoundException
|
if (habits.size == 1) return HistoryWidget(context, id, habits[0])
|
||||||
val habit = getHabitFromWidgetId(id)
|
else return StackWidget(context, id, StackWidgetType.HISTORY, habits)
|
||||||
if (habit != null) {
|
|
||||||
return HistoryWidget(context, id, habit)
|
|
||||||
} else {
|
|
||||||
return StackWidget(context, id, StackWidgetType.HISTORY)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,15 +24,13 @@ import android.view.*
|
|||||||
import org.isoron.uhabits.activities.common.views.*
|
import org.isoron.uhabits.activities.common.views.*
|
||||||
import org.isoron.uhabits.activities.habits.show.views.*
|
import org.isoron.uhabits.activities.habits.show.views.*
|
||||||
import org.isoron.uhabits.core.models.*
|
import org.isoron.uhabits.core.models.*
|
||||||
import org.isoron.uhabits.core.preferences.*
|
|
||||||
import org.isoron.uhabits.utils.*
|
import org.isoron.uhabits.utils.*
|
||||||
import org.isoron.uhabits.widgets.views.*
|
import org.isoron.uhabits.widgets.views.*
|
||||||
|
|
||||||
class ScoreWidget(
|
class ScoreWidget(
|
||||||
context: Context,
|
context: Context,
|
||||||
id: Int,
|
id: Int,
|
||||||
private val habit: Habit,
|
private val habit: Habit
|
||||||
private val prefs: Preferences
|
|
||||||
) : BaseWidget(context, id) {
|
) : BaseWidget(context, id) {
|
||||||
|
|
||||||
override fun getOnClickPendingIntent(context: Context) =
|
override fun getOnClickPendingIntent(context: Context) =
|
||||||
|
|||||||
@@ -18,19 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.isoron.uhabits.widgets
|
package org.isoron.uhabits.widgets
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.*
|
||||||
import org.isoron.uhabits.HabitsApplication
|
|
||||||
|
|
||||||
class ScoreWidgetProvider : BaseWidgetProvider() {
|
class ScoreWidgetProvider : BaseWidgetProvider() {
|
||||||
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
||||||
// if the habit was null, but did not have a habit id associated with a stack widget,
|
val habits = getHabitsFromWidgetId(id)
|
||||||
// `getHabitFromWidgetId` will throw a HabitNotFoundException
|
if (habits.size == 1) return ScoreWidget(context, id, habits[0])
|
||||||
val habit = getHabitFromWidgetId(id)
|
else return StackWidget(context, id, StackWidgetType.SCORE, habits)
|
||||||
val component = (context.applicationContext as HabitsApplication).component
|
|
||||||
if (habit != null) {
|
|
||||||
return ScoreWidget(context, id, habit, component.preferences)
|
|
||||||
} else {
|
|
||||||
return StackWidget(context, id, StackWidgetType.SCORE)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,17 +19,19 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.widgets
|
package org.isoron.uhabits.widgets
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.*
|
||||||
import android.content.Context
|
import android.content.*
|
||||||
import android.content.Intent
|
import android.net.*
|
||||||
import android.net.Uri
|
import android.view.*
|
||||||
import android.view.View
|
import android.widget.*
|
||||||
import android.widget.RemoteViews
|
import org.isoron.uhabits.core.models.*
|
||||||
|
import org.isoron.uhabits.core.utils.*
|
||||||
|
|
||||||
class StackWidget(
|
class StackWidget(
|
||||||
context: Context,
|
context: Context,
|
||||||
widgetId: Int,
|
widgetId: Int,
|
||||||
private val widgetType: StackWidgetType
|
private val widgetType: StackWidgetType,
|
||||||
|
private val habits: List<Habit>
|
||||||
) : BaseWidget(context, widgetId) {
|
) : BaseWidget(context, widgetId) {
|
||||||
|
|
||||||
override fun getOnClickPendingIntent(context: Context) = null
|
override fun getOnClickPendingIntent(context: Context) = null
|
||||||
@@ -39,13 +41,17 @@ class StackWidget(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getRemoteViews(width: Int, height: Int): RemoteViews {
|
override fun getRemoteViews(width: Int, height: Int): RemoteViews {
|
||||||
|
val manager = AppWidgetManager.getInstance(context)
|
||||||
val remoteViews = RemoteViews(context.packageName, StackWidgetType.getStackWidgetLayoutId(widgetType))
|
val remoteViews = RemoteViews(context.packageName, StackWidgetType.getStackWidgetLayoutId(widgetType))
|
||||||
val serviceIntent = Intent(context, StackWidgetService::class.java)
|
val serviceIntent = Intent(context, StackWidgetService::class.java)
|
||||||
|
val habitIds = StringUtils.joinLongs(habits.map { it.id!! }.toLongArray())
|
||||||
|
|
||||||
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id)
|
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id)
|
||||||
serviceIntent.putExtra(StackWidgetService.WIDGET_TYPE, widgetType.value)
|
serviceIntent.putExtra(StackWidgetService.WIDGET_TYPE, widgetType.value)
|
||||||
serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)))
|
serviceIntent.putExtra(StackWidgetService.HABIT_IDS, habitIds)
|
||||||
|
serviceIntent.data = Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME))
|
||||||
remoteViews.setRemoteAdapter(StackWidgetType.getStackWidgetAdapterViewId(widgetType), serviceIntent)
|
remoteViews.setRemoteAdapter(StackWidgetType.getStackWidgetAdapterViewId(widgetType), serviceIntent)
|
||||||
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(id, StackWidgetType.getStackWidgetAdapterViewId(widgetType))
|
manager.notifyAppWidgetViewDataChanged(id, StackWidgetType.getStackWidgetAdapterViewId(widgetType))
|
||||||
// TODO what should the empty view look like?
|
// TODO what should the empty view look like?
|
||||||
remoteViews.setEmptyView(StackWidgetType.getStackWidgetAdapterViewId(widgetType),
|
remoteViews.setEmptyView(StackWidgetType.getStackWidgetAdapterViewId(widgetType),
|
||||||
StackWidgetType.getStackWidgetEmptyViewId(widgetType))
|
StackWidgetType.getStackWidgetEmptyViewId(widgetType))
|
||||||
|
|||||||
@@ -1,110 +1,127 @@
|
|||||||
package org.isoron.uhabits.widgets;
|
package org.isoron.uhabits.widgets;
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.*;
|
||||||
import android.content.Context;
|
import android.content.*;
|
||||||
import android.content.Intent;
|
import android.os.*;
|
||||||
import android.os.Bundle;
|
import android.support.annotation.*;
|
||||||
import android.os.Handler;
|
import android.widget.*;
|
||||||
import android.os.Looper;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
import android.widget.RemoteViewsService;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.HabitsApplication;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.core.models.Habit;
|
import org.isoron.uhabits.core.models.*;
|
||||||
|
import org.isoron.uhabits.core.utils.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
|
|
||||||
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT;
|
import static android.appwidget.AppWidgetManager.*;
|
||||||
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH;
|
|
||||||
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT;
|
|
||||||
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH;
|
|
||||||
import static org.isoron.androidbase.utils.InterfaceUtils.dpToPixels;
|
import static org.isoron.androidbase.utils.InterfaceUtils.dpToPixels;
|
||||||
import static org.isoron.uhabits.widgets.StackWidgetService.WIDGET_TYPE;
|
import static org.isoron.uhabits.widgets.StackWidgetService.*;
|
||||||
|
|
||||||
public class StackWidgetService extends RemoteViewsService {
|
|
||||||
|
|
||||||
|
public class StackWidgetService extends RemoteViewsService
|
||||||
|
{
|
||||||
public static final String WIDGET_TYPE = "WIDGET_TYPE";
|
public static final String WIDGET_TYPE = "WIDGET_TYPE";
|
||||||
|
public static final String HABIT_IDS = "HABIT_IDS";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RemoteViewsFactory onGetViewFactory(Intent intent) {
|
public RemoteViewsFactory onGetViewFactory(Intent intent)
|
||||||
|
{
|
||||||
return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
|
return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
|
class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
|
||||||
private Context mContext;
|
{
|
||||||
private int mAppWidgetId;
|
private Context context;
|
||||||
private ArrayList<Habit> mHabitList;
|
private int widgetId;
|
||||||
private StackWidgetType mWidgetType;
|
private long[] habitIds;
|
||||||
|
private ArrayList<Habit> habits = new ArrayList<>();
|
||||||
|
private StackWidgetType widgetType;
|
||||||
|
|
||||||
public StackRemoteViewsFactory(Context context, Intent intent) {
|
public StackRemoteViewsFactory(Context context, Intent intent)
|
||||||
mContext = context;
|
{
|
||||||
mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
|
this.context = context;
|
||||||
|
widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
|
||||||
|
AppWidgetManager.INVALID_APPWIDGET_ID);
|
||||||
int widgetTypeValue = intent.getIntExtra(WIDGET_TYPE, -1);
|
int widgetTypeValue = intent.getIntExtra(WIDGET_TYPE, -1);
|
||||||
if (widgetTypeValue != -1) {
|
String habitIdsStr = intent.getStringExtra(HABIT_IDS);
|
||||||
mWidgetType = StackWidgetType.getWidgetTypeFromValue(widgetTypeValue);
|
|
||||||
}
|
if (widgetTypeValue < 0) throw new RuntimeException("invalid widget type");
|
||||||
|
if (habitIdsStr == null) throw new RuntimeException("habitIdsStr is null");
|
||||||
|
|
||||||
|
widgetType = StackWidgetType.getWidgetTypeFromValue(widgetTypeValue);
|
||||||
|
habitIds = StringUtils.splitLongs(habitIdsStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCreate() {
|
public void onCreate()
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDestroy() {
|
public void onDestroy()
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCount() {
|
public int getCount()
|
||||||
return mHabitList.size();
|
{
|
||||||
|
return habits.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public WidgetDimensions getDimensionsFromOptions(@NonNull Context ctx,
|
public WidgetDimensions getDimensionsFromOptions(@NonNull Context ctx,
|
||||||
@NonNull Bundle options) {
|
@NonNull Bundle options)
|
||||||
|
{
|
||||||
int maxWidth =
|
int maxWidth =
|
||||||
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_WIDTH));
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_WIDTH));
|
||||||
int maxHeight =
|
int maxHeight =
|
||||||
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_HEIGHT));
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_HEIGHT));
|
||||||
int minWidth =
|
int minWidth =
|
||||||
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_WIDTH));
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_WIDTH));
|
||||||
int minHeight =
|
int minHeight =
|
||||||
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_HEIGHT));
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_HEIGHT));
|
||||||
|
|
||||||
return new WidgetDimensions(minWidth, maxHeight, maxWidth, minHeight);
|
return new WidgetDimensions(minWidth, maxHeight, maxWidth, minHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteViews getViewAt(int position) {
|
public RemoteViews getViewAt(int position)
|
||||||
|
{
|
||||||
RemoteViews rv = null;
|
RemoteViews rv = null;
|
||||||
if (position < getCount()) {
|
if (position < getCount())
|
||||||
Habit habit = mHabitList.get(position);
|
{
|
||||||
|
Habit habit = habits.get(position);
|
||||||
BaseWidget widget = initializeWidget(habit);
|
BaseWidget widget = initializeWidget(habit);
|
||||||
Bundle options = AppWidgetManager.getInstance(mContext).getAppWidgetOptions(mAppWidgetId);
|
Bundle options =
|
||||||
widget.setDimensions(getDimensionsFromOptions(mContext, options));
|
AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId);
|
||||||
|
widget.setDimensions(getDimensionsFromOptions(context, options));
|
||||||
final RemoteViews[] landscape = new RemoteViews[1];
|
final RemoteViews[] landscape = new RemoteViews[1];
|
||||||
final RemoteViews[] portrait = new RemoteViews[1];
|
final RemoteViews[] portrait = new RemoteViews[1];
|
||||||
|
|
||||||
Object lock = new Object();
|
Object lock = new Object();
|
||||||
final boolean[] flag = {false};
|
final boolean[] flag = {false};
|
||||||
|
|
||||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
new Handler(Looper.getMainLooper()).post(() ->
|
||||||
@Override
|
{
|
||||||
public void run() {
|
synchronized (lock)
|
||||||
synchronized (lock) {
|
{
|
||||||
landscape[0] = widget.getLandscapeRemoteViews();
|
landscape[0] =
|
||||||
portrait[0] = widget.getPortraitRemoteViews();
|
widget.getLandscapeRemoteViews();
|
||||||
flag[0] = true;
|
portrait[0] =
|
||||||
lock.notifyAll();
|
widget.getPortraitRemoteViews();
|
||||||
}
|
flag[0] = true;
|
||||||
}
|
lock.notifyAll();
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
synchronized (lock) {
|
synchronized (lock)
|
||||||
while (!flag[0]) {
|
{
|
||||||
try {
|
while (!flag[0])
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
lock.wait();
|
lock.wait();
|
||||||
} catch (InterruptedException e) {
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,44 +132,55 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BaseWidget initializeWidget(Habit habit) {
|
private BaseWidget initializeWidget(Habit habit)
|
||||||
switch (mWidgetType) {
|
{
|
||||||
|
switch (widgetType)
|
||||||
|
{
|
||||||
case CHECKMARK:
|
case CHECKMARK:
|
||||||
return new CheckmarkWidget(mContext, mAppWidgetId, habit);
|
return new CheckmarkWidget(context, widgetId, habit);
|
||||||
case FREQUENCY:
|
case FREQUENCY:
|
||||||
return new FrequencyWidget(mContext, mAppWidgetId, habit);
|
return new FrequencyWidget(context, widgetId, habit);
|
||||||
case SCORE:
|
case SCORE:
|
||||||
HabitsApplication app = (HabitsApplication) mContext.getApplicationContext();
|
return new ScoreWidget(context, widgetId, habit);
|
||||||
return new ScoreWidget(mContext, mAppWidgetId, habit, app.getComponent().getPreferences());
|
|
||||||
case HISTORY:
|
case HISTORY:
|
||||||
return new HistoryWidget(mContext, mAppWidgetId, habit);
|
return new HistoryWidget(context, widgetId, habit);
|
||||||
case STREAKS:
|
case STREAKS:
|
||||||
return new StreakWidget(mContext, mAppWidgetId, habit);
|
return new StreakWidget(context, widgetId, habit);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteViews getLoadingView() {
|
public RemoteViews getLoadingView()
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getViewTypeCount() {
|
public int getViewTypeCount()
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getItemId(int position) {
|
public long getItemId(int position)
|
||||||
|
{
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasStableIds() {
|
public boolean hasStableIds()
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDataSetChanged() {
|
public void onDataSetChanged()
|
||||||
mHabitList = new ArrayList<>();
|
{
|
||||||
HabitsApplication app = (HabitsApplication) mContext.getApplicationContext();
|
habits.clear();
|
||||||
for (Habit h : app.getComponent().getHabitList()) {
|
HabitsApplication app = (HabitsApplication) context.getApplicationContext();
|
||||||
mHabitList.add(h);
|
HabitList habitList = app.getComponent().getHabitList();
|
||||||
|
|
||||||
|
for (long id : habitIds)
|
||||||
|
{
|
||||||
|
Habit h = habitList.getById(id);
|
||||||
|
if (h == null) throw new HabitNotFoundException();
|
||||||
|
habits.add(h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.isoron.uhabits.widgets
|
package org.isoron.uhabits.widgets
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.*
|
||||||
|
|
||||||
class StreakWidgetProvider : BaseWidgetProvider() {
|
class StreakWidgetProvider : BaseWidgetProvider() {
|
||||||
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
||||||
// if the habit was null, but did not have a habit id associated with a stack widget,
|
val habits = getHabitsFromWidgetId(id)
|
||||||
// `getHabitFromWidgetId` will throw a HabitNotFoundException
|
if (habits.size == 1) return StreakWidget(context, id, habits[0])
|
||||||
val habit = getHabitFromWidgetId(id)
|
else return StackWidget(context, id, StackWidgetType.STREAKS, habits)
|
||||||
if (habit != null) {
|
|
||||||
return StreakWidget(context, id, habit)
|
|
||||||
} else {
|
|
||||||
return StackWidget(context, id, StackWidgetType.STREAKS)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,12 +22,6 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/createStackWidgetButton"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:text="@string/create_stackview_widget_button"/>
|
|
||||||
|
|
||||||
<ListView
|
<ListView
|
||||||
android:id="@+id/listView"
|
android:id="@+id/listView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -36,4 +30,10 @@
|
|||||||
android:layout_weight="1">
|
android:layout_weight="1">
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonSave"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:text="@string/save"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user