mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
Code review changes; Made 'stack view' design available for all widgets
This commit is contained in:
@@ -24,6 +24,7 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
buildToolsVersion '26.0.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -18,6 +18,7 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
buildToolsVersion '26.0.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -5,7 +5,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.0-beta6'
|
||||
classpath 'com.android.tools.build:gradle:3.0.0'
|
||||
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
|
||||
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.4'
|
||||
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
|
||||
|
||||
@@ -89,6 +89,7 @@ android {
|
||||
sourceSets {
|
||||
main.assets.srcDirs += '../uhabits-core/src/main/resources/'
|
||||
}
|
||||
buildToolsVersion '26.0.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -84,13 +84,6 @@
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".widgets.HabitGroupPickerDialog"
|
||||
android:theme="@style/Theme.AppCompat.Light.Dialog">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.about.AboutActivity"
|
||||
android:label="@string/about">
|
||||
@@ -110,7 +103,7 @@
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_checkmark_info"/>
|
||||
</receiver>
|
||||
<service android:name=".widgets.CheckmarkStackWidgetService"
|
||||
<service android:name=".widgets.StackWidgetService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS"
|
||||
android:exported="false" />
|
||||
<receiver
|
||||
|
||||
@@ -141,10 +141,12 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
}).start();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected Habit getHabitFromWidgetId(int widgetId)
|
||||
{
|
||||
long habitId = widgetPrefs.getHabitIdFromWidgetId(widgetId);
|
||||
if (habitId == WidgetPreferences.STACK_WIDGET_HABITS) {
|
||||
return null;
|
||||
}
|
||||
Habit habit = habits.getById(habitId);
|
||||
if (habit == null) throw new HabitNotFoundException();
|
||||
return habit;
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package org.isoron.uhabits.widgets
|
||||
|
||||
import android.content.Context
|
||||
import org.isoron.uhabits.HabitsApplication
|
||||
|
||||
class CheckmarkStackWidgetProvider : BaseWidgetProvider() {
|
||||
|
||||
override fun getWidgetFromId(context: Context, id: Int): CheckmarkStackWidget {
|
||||
val habitIds = getHabitGroupFromWidget(context, id)
|
||||
return CheckmarkStackWidget(context, id, habitIds)
|
||||
}
|
||||
|
||||
private fun getHabitGroupFromWidget(context: Context, widgetId: Int) : List<Long> {
|
||||
val app = context.getApplicationContext() as HabitsApplication
|
||||
val widgetPrefs = app.component.widgetPreferences
|
||||
val habitIds = widgetPrefs.getHabitIdsGroupFromWidgetId(widgetId)
|
||||
return habitIds
|
||||
}
|
||||
}
|
||||
@@ -18,24 +18,17 @@
|
||||
*/
|
||||
package org.isoron.uhabits.widgets
|
||||
|
||||
import android.content.*
|
||||
import org.isoron.uhabits.HabitsApplication
|
||||
import android.content.Context
|
||||
|
||||
class CheckmarkWidgetProvider : BaseWidgetProvider() {
|
||||
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
||||
try {
|
||||
val habit = getHabitFromWidgetId(id)
|
||||
// if the habit was null, but did not have a habit id associated with a stack widget,
|
||||
// `getHabitFromWidgetId` will throw a HabitNotFoundException
|
||||
val habit = getHabitFromWidgetId(id)
|
||||
if (habit != null) {
|
||||
return CheckmarkWidget(context, id, habit)
|
||||
} catch (e: Exception) {
|
||||
val habitIds = getHabitIdsGroupFromWidget(context, id)
|
||||
return CheckmarkStackWidget(context, id, habitIds)
|
||||
} else {
|
||||
return StackWidget(context, id, StackWidgetType.CHECKMARK)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getHabitIdsGroupFromWidget(context: Context, widgetId: Int) : List<Long> {
|
||||
val app = context.getApplicationContext() as HabitsApplication
|
||||
val widgetPrefs = app.component.widgetPreferences
|
||||
val habitIds = widgetPrefs.getHabitIdsGroupFromWidgetId(widgetId)
|
||||
return habitIds
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,17 @@
|
||||
|
||||
package org.isoron.uhabits.widgets
|
||||
|
||||
import android.content.*
|
||||
import android.content.Context
|
||||
|
||||
class FrequencyWidgetProvider : BaseWidgetProvider() {
|
||||
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,
|
||||
// `getHabitFromWidgetId` will throw a HabitNotFoundException
|
||||
val habit = getHabitFromWidgetId(id)
|
||||
return FrequencyWidget(context, id, habit)
|
||||
if (habit != null) {
|
||||
return FrequencyWidget(context, id, habit)
|
||||
} else {
|
||||
return StackWidget(context, id, StackWidgetType.FREQUENCY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.widgets
|
||||
|
||||
import android.app.Activity
|
||||
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
|
||||
import android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import android.widget.CompoundButton
|
||||
import org.isoron.uhabits.HabitsApplication
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.models.HabitList
|
||||
import org.isoron.uhabits.core.preferences.WidgetPreferences
|
||||
|
||||
class HabitGroupPickerDialog : Activity(), AdapterView.OnItemClickListener {
|
||||
|
||||
private var widgetId = 0
|
||||
private lateinit var habitList: HabitList
|
||||
private lateinit var preferences: WidgetPreferences
|
||||
private lateinit var habitIds: ArrayList<Long>
|
||||
private lateinit var widgetUpdater: WidgetUpdater
|
||||
private lateinit var habitIdsSelected: ArrayList<Long>
|
||||
private lateinit var habitListView: ListView
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val component = (applicationContext as HabitsApplication).component
|
||||
habitList = component.habitList
|
||||
preferences = component.widgetPreferences
|
||||
widgetUpdater = component.widgetUpdater
|
||||
widgetId = intent.extras?.getInt(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID) ?: 0
|
||||
habitIdsSelected = ArrayList<Long>()
|
||||
|
||||
habitIds = ArrayList<Long>()
|
||||
val habitNames = ArrayList<String>()
|
||||
for (h in habitList) {
|
||||
if (h.isArchived) continue
|
||||
habitIds.add(h.getId()!!)
|
||||
habitNames.add(h.name)
|
||||
}
|
||||
|
||||
setContentView(R.layout.stack_widget_configure_activity)
|
||||
habitListView = findViewById(R.id.stackWidgetListView) as ListView
|
||||
with(habitListView) {
|
||||
adapter = ListAdapter(context, R.layout.habit_checkbox_list_item,
|
||||
R.id.listItemHabitName, R.id.listItemHabitCheckbox, habitNames)
|
||||
onItemClickListener = this@HabitGroupPickerDialog
|
||||
}
|
||||
with(findViewById(R.id.doneConfigureButton) as Button) {
|
||||
setOnClickListener {
|
||||
if (habitIdsSelected.size == 1) {
|
||||
preferences.addWidget(widgetId, habitIdsSelected.first())
|
||||
widgetUpdater.updateWidgets()
|
||||
setResult(Activity.RESULT_OK, Intent().apply {
|
||||
putExtra(EXTRA_APPWIDGET_ID, widgetId)
|
||||
})
|
||||
finish()
|
||||
} else if (!habitIdsSelected.isEmpty()) {
|
||||
preferences.addWidget(widgetId, habitIdsSelected.toString())
|
||||
widgetUpdater.updateWidgets()
|
||||
setResult(Activity.RESULT_OK, Intent().apply {
|
||||
putExtra(EXTRA_APPWIDGET_ID, widgetId)
|
||||
})
|
||||
finish()
|
||||
} else {
|
||||
Toast.makeText(context, getString(R.string.select_habit_requirement_prompt),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemClick(parent: AdapterView<*>,
|
||||
view: View,
|
||||
position: Int,
|
||||
id: Long) {
|
||||
val checkbox = view.findViewById(R.id.listItemHabitCheckbox) as CheckBox
|
||||
checkbox.isChecked = !checkbox.isChecked
|
||||
}
|
||||
|
||||
private inner class ListAdapter(context: Context,
|
||||
private var layoutResource: Int,
|
||||
private var textViewResourceId: Int,
|
||||
private var checkBoxResourceId: Int,
|
||||
private var habitNames: List<String>) :
|
||||
ArrayAdapter<String>(context, layoutResource, textViewResourceId, habitNames) {
|
||||
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
val layoutInflater: LayoutInflater = LayoutInflater.from(context)
|
||||
val view = layoutInflater.inflate(layoutResource, null)
|
||||
|
||||
val item = getItem(position)
|
||||
if (item != null) {
|
||||
val tv = view.findViewById(textViewResourceId) as TextView
|
||||
tv.text = habitNames.get(position)
|
||||
val cb = view.findViewById(checkBoxResourceId) as CheckBox
|
||||
cb.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
||||
if (isChecked) {
|
||||
habitIdsSelected.add(habitIds.get(position))
|
||||
} else {
|
||||
habitIdsSelected.remove(habitIds.get(position))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import android.app.*
|
||||
import android.appwidget.AppWidgetManager.*
|
||||
import android.content.*
|
||||
import android.os.*
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import android.widget.*
|
||||
import org.isoron.uhabits.*
|
||||
@@ -61,6 +62,16 @@ class HabitPickerDialog : Activity(), AdapterView.OnItemClickListener {
|
||||
habitNames)
|
||||
onItemClickListener = this@HabitPickerDialog
|
||||
}
|
||||
with(findViewById(R.id.createStackWidgetButton) as Button) {
|
||||
setOnClickListener(View.OnClickListener {
|
||||
preferences.addWidget(widgetId, WidgetPreferences.STACK_WIDGET_HABITS)
|
||||
widgetUpdater.updateWidgets()
|
||||
setResult(Activity.RESULT_OK, Intent().apply {
|
||||
putExtra(EXTRA_APPWIDGET_ID, widgetId)
|
||||
})
|
||||
finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemClick(parent: AdapterView<*>,
|
||||
|
||||
@@ -18,11 +18,17 @@
|
||||
*/
|
||||
package org.isoron.uhabits.widgets
|
||||
|
||||
import android.content.*
|
||||
import android.content.Context
|
||||
|
||||
class HistoryWidgetProvider : BaseWidgetProvider() {
|
||||
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,
|
||||
// `getHabitFromWidgetId` will throw a HabitNotFoundException
|
||||
val habit = getHabitFromWidgetId(id)
|
||||
return HistoryWidget(context, id, habit)
|
||||
if (habit != null) {
|
||||
return HistoryWidget(context, id, habit)
|
||||
} else {
|
||||
return StackWidget(context, id, StackWidgetType.HISTORY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,19 @@
|
||||
*/
|
||||
package org.isoron.uhabits.widgets
|
||||
|
||||
import android.content.*
|
||||
import org.isoron.uhabits.*
|
||||
import android.content.Context
|
||||
import org.isoron.uhabits.HabitsApplication
|
||||
|
||||
class ScoreWidgetProvider : BaseWidgetProvider() {
|
||||
override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
|
||||
val component = (context.applicationContext as HabitsApplication).component
|
||||
// if the habit was null, but did not have a habit id associated with a stack widget,
|
||||
// `getHabitFromWidgetId` will throw a HabitNotFoundException
|
||||
val habit = getHabitFromWidgetId(id)
|
||||
return ScoreWidget(context, id, habit, component.preferences)
|
||||
val component = (context.applicationContext as HabitsApplication).component
|
||||
if (habit != null) {
|
||||
return ScoreWidget(context, id, habit, component.preferences)
|
||||
} else {
|
||||
return StackWidget(context, id, StackWidgetType.SCORE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,14 @@ package org.isoron.uhabits.widgets
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import org.isoron.uhabits.R
|
||||
|
||||
class CheckmarkStackWidget(
|
||||
class StackWidget(
|
||||
context: Context,
|
||||
widgetId: Int,
|
||||
private val habitIds: List<Long>
|
||||
private val widgetType: StackWidgetType
|
||||
) : BaseWidget(context, widgetId) {
|
||||
|
||||
override fun getOnClickPendingIntent(context: Context) = null
|
||||
@@ -39,14 +39,16 @@ class CheckmarkStackWidget(
|
||||
}
|
||||
|
||||
override fun getRemoteViews(width: Int, height: Int): RemoteViews {
|
||||
val remoteViews = RemoteViews(context.packageName, R.layout.stackview_widget)
|
||||
val serviceIntent = Intent(context, CheckmarkStackWidgetService::class.java)
|
||||
val remoteViews = RemoteViews(context.packageName, StackWidgetType.getStackWidgetLayoutId(widgetType))
|
||||
val serviceIntent = Intent(context, StackWidgetService::class.java)
|
||||
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id)
|
||||
serviceIntent.putExtra(CheckmarkStackWidgetService.HABIT_IDS_SELECTED, habitIds.toLongArray())
|
||||
remoteViews.setRemoteAdapter(R.id.stackWidgetView, serviceIntent)
|
||||
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(id, R.id.stackWidgetView)
|
||||
serviceIntent.putExtra(StackWidgetService.WIDGET_TYPE, widgetType.value)
|
||||
serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)))
|
||||
remoteViews.setRemoteAdapter(StackWidgetType.getStackWidgetAdapterViewId(widgetType), serviceIntent)
|
||||
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(id, StackWidgetType.getStackWidgetAdapterViewId(widgetType))
|
||||
// TODO what should the empty view look like?
|
||||
remoteViews.setEmptyView(R.id.stackWidgetView, R.id.stackWidgetEmptyView)
|
||||
remoteViews.setEmptyView(StackWidgetType.getStackWidgetAdapterViewId(widgetType),
|
||||
StackWidgetType.getStackWidgetEmptyViewId(widgetType))
|
||||
return remoteViews
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.RemoteViewsService;
|
||||
@@ -12,37 +14,36 @@ import org.isoron.uhabits.HabitsApplication;
|
||||
import org.isoron.uhabits.core.models.Habit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT;
|
||||
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.uhabits.widgets.CheckmarkStackWidgetService.HABIT_IDS_SELECTED;
|
||||
import static org.isoron.uhabits.widgets.StackWidgetService.WIDGET_TYPE;
|
||||
|
||||
public class CheckmarkStackWidgetService extends RemoteViewsService {
|
||||
public class StackWidgetService extends RemoteViewsService {
|
||||
|
||||
public static final String HABIT_IDS_SELECTED = "HABIT_IDS_SELECTED";
|
||||
public static final String WIDGET_TYPE = "WIDGET_TYPE";
|
||||
|
||||
@Override
|
||||
public RemoteViewsFactory onGetViewFactory(Intent intent) {
|
||||
return new CheckmarkStackRemoteViewsFactory(this.getApplicationContext(), intent);
|
||||
return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
|
||||
}
|
||||
}
|
||||
|
||||
class CheckmarkStackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
|
||||
class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
|
||||
private Context mContext;
|
||||
private int mAppWidgetId;
|
||||
private ArrayList<Habit> mHabitList;
|
||||
private List<Long> mHabitsSelected;
|
||||
private StackWidgetType mWidgetType;
|
||||
|
||||
public CheckmarkStackRemoteViewsFactory(Context context, Intent intent) {
|
||||
public StackRemoteViewsFactory(Context context, Intent intent) {
|
||||
mContext = context;
|
||||
mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
|
||||
mHabitsSelected = new ArrayList<>();
|
||||
for (long id : intent.getLongArrayExtra(HABIT_IDS_SELECTED)) {
|
||||
mHabitsSelected.add(id);
|
||||
int widgetTypeValue = intent.getIntExtra(WIDGET_TYPE, -1);
|
||||
if (widgetTypeValue != -1) {
|
||||
mWidgetType = StackWidgetType.getWidgetTypeFromValue(widgetTypeValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +52,7 @@ class CheckmarkStackRemoteViewsFactory implements RemoteViewsService.RemoteViews
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
mHabitList.clear();
|
||||
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
@@ -75,20 +76,62 @@ class CheckmarkStackRemoteViewsFactory implements RemoteViewsService.RemoteViews
|
||||
|
||||
public RemoteViews getViewAt(int position) {
|
||||
RemoteViews rv = null;
|
||||
|
||||
if (position < getCount()) {
|
||||
Habit habit = mHabitList.get(position);
|
||||
CheckmarkWidget checkmarkWidget = new CheckmarkWidget(mContext, mAppWidgetId, habit);
|
||||
BaseWidget widget = initializeWidget(habit);
|
||||
Bundle options = AppWidgetManager.getInstance(mContext).getAppWidgetOptions(mAppWidgetId);
|
||||
checkmarkWidget.setDimensions(getDimensionsFromOptions(mContext, options));
|
||||
RemoteViews landscape = checkmarkWidget.getLandscapeRemoteViews();
|
||||
RemoteViews portrait = checkmarkWidget.getPortraitRemoteViews();
|
||||
rv = new RemoteViews(landscape, portrait);
|
||||
widget.setDimensions(getDimensionsFromOptions(mContext, options));
|
||||
final RemoteViews[] landscape = new RemoteViews[1];
|
||||
final RemoteViews[] portrait = new RemoteViews[1];
|
||||
|
||||
Object lock = new Object();
|
||||
final boolean[] flag = {false};
|
||||
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (lock) {
|
||||
landscape[0] = widget.getLandscapeRemoteViews();
|
||||
portrait[0] = widget.getPortraitRemoteViews();
|
||||
flag[0] = true;
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
synchronized (lock) {
|
||||
while (!flag[0]) {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rv = new RemoteViews(landscape[0], portrait[0]);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
private BaseWidget initializeWidget(Habit habit) {
|
||||
switch (mWidgetType) {
|
||||
case CHECKMARK:
|
||||
return new CheckmarkWidget(mContext, mAppWidgetId, habit);
|
||||
case FREQUENCY:
|
||||
return new FrequencyWidget(mContext, mAppWidgetId, habit);
|
||||
case SCORE:
|
||||
HabitsApplication app = (HabitsApplication) mContext.getApplicationContext();
|
||||
return new ScoreWidget(mContext, mAppWidgetId, habit, app.getComponent().getPreferences());
|
||||
case HISTORY:
|
||||
return new HistoryWidget(mContext, mAppWidgetId, habit);
|
||||
case STREAKS:
|
||||
return new StreakWidget(mContext, mAppWidgetId, habit);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public RemoteViews getLoadingView() {
|
||||
return null;
|
||||
}
|
||||
@@ -109,9 +152,7 @@ class CheckmarkStackRemoteViewsFactory implements RemoteViewsService.RemoteViews
|
||||
mHabitList = new ArrayList<>();
|
||||
HabitsApplication app = (HabitsApplication) mContext.getApplicationContext();
|
||||
for (Habit h : app.getComponent().getHabitList()) {
|
||||
if (mHabitsSelected.contains(h.getId())) {
|
||||
mHabitList.add(h);
|
||||
}
|
||||
mHabitList.add(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package org.isoron.uhabits.widgets;
|
||||
|
||||
import org.isoron.uhabits.R;
|
||||
|
||||
/**
|
||||
* Created by victoryu on 11/3/17.
|
||||
*/
|
||||
|
||||
public enum StackWidgetType {
|
||||
|
||||
CHECKMARK(0),
|
||||
FREQUENCY(1),
|
||||
SCORE(2), // habit strength widget
|
||||
HISTORY(3),
|
||||
STREAKS(4);
|
||||
|
||||
private int value;
|
||||
StackWidgetType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static StackWidgetType getWidgetTypeFromValue(int value) {
|
||||
if (CHECKMARK.getValue() == value) {
|
||||
return CHECKMARK;
|
||||
} else if (FREQUENCY.getValue() == value) {
|
||||
return FREQUENCY;
|
||||
} else if (SCORE.getValue() == value) {
|
||||
return SCORE;
|
||||
} else if (HISTORY.getValue() == value) {
|
||||
return HISTORY;
|
||||
} else if (STREAKS.getValue() == value) {
|
||||
return STREAKS;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int getStackWidgetLayoutId(StackWidgetType type) {
|
||||
switch (type) {
|
||||
case CHECKMARK:
|
||||
return R.layout.checkmark_stackview_widget;
|
||||
case FREQUENCY:
|
||||
return R.layout.frequency_stackview_widget;
|
||||
case SCORE:
|
||||
return R.layout.score_stackview_widget;
|
||||
case HISTORY:
|
||||
return R.layout.history_stackview_widget;
|
||||
case STREAKS:
|
||||
return R.layout.streak_stackview_widget;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getStackWidgetAdapterViewId(StackWidgetType type) {
|
||||
switch (type) {
|
||||
case CHECKMARK:
|
||||
return R.id.checkmarkStackWidgetView;
|
||||
case FREQUENCY:
|
||||
return R.id.frequencyStackWidgetView;
|
||||
case SCORE:
|
||||
return R.id.scoreStackWidgetView;
|
||||
case HISTORY:
|
||||
return R.id.historyStackWidgetView;
|
||||
case STREAKS:
|
||||
return R.id.streakStackWidgetView;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getStackWidgetEmptyViewId(StackWidgetType type) {
|
||||
switch (type) {
|
||||
case CHECKMARK:
|
||||
return R.id.checkmarkStackWidgetEmptyView;
|
||||
case FREQUENCY:
|
||||
return R.id.frequencyStackWidgetEmptyView;
|
||||
case SCORE:
|
||||
return R.id.scoreStackWidgetEmptyView;
|
||||
case HISTORY:
|
||||
return R.id.historyStackWidgetEmptyView;
|
||||
case STREAKS:
|
||||
return R.id.streakStackWidgetEmptyView;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,11 +18,17 @@
|
||||
*/
|
||||
package org.isoron.uhabits.widgets
|
||||
|
||||
import android.content.*
|
||||
import android.content.Context
|
||||
|
||||
class StreakWidgetProvider : BaseWidgetProvider() {
|
||||
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,
|
||||
// `getHabitFromWidgetId` will throw a HabitNotFoundException
|
||||
val habit = getHabitFromWidgetId(id)
|
||||
return StreakWidget(context, id, habit)
|
||||
if (habit != null) {
|
||||
return StreakWidget(context, id, habit)
|
||||
} else {
|
||||
return StackWidget(context, id, StackWidgetType.STREAKS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<StackView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/stackWidgetView"
|
||||
android:id="@+id/checkmarkStackWidgetView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:loopViews="true" />
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/stackWidgetEmptyView"
|
||||
android:id="@+id/checkmarkStackWidgetEmptyView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/checkmark_stack_widget"
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<StackView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/frequencyStackWidgetView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:loopViews="true" />
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/frequencyStackWidgetEmptyView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/frequency_stack_widget"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp" />
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<StackView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/historyStackWidgetView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:loopViews="true" />
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/historyStackWidgetEmptyView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/history_stack_widget"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp" />
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<StackView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/scoreStackWidgetView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:loopViews="true" />
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/scoreStackWidgetEmptyView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/score_stack_widget"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp" />
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<StackView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/streakStackWidgetView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:loopViews="true" />
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/streakStackWidgetEmptyView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/streaks_stack_widget"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp" />
|
||||
</FrameLayout>
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
~
|
||||
~ This file is part of Loop Habit Tracker.
|
||||
@@ -18,10 +17,23 @@
|
||||
~ with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<ListView android:id="@+id/listView"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
</ListView>
|
||||
<Button
|
||||
android:id="@+id/createStackWidgetButton"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:text="@string/create_stackview_widget_button"/>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/listView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1">
|
||||
</ListView>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -125,7 +125,13 @@
|
||||
<string name="version_n">Version %s</string>
|
||||
<string name="frequency">Frequency</string>
|
||||
<string name="checkmark">Checkmark</string>
|
||||
<string name="create_stackview_widget_button">StackView Widget For All Habits</string>
|
||||
<string name="checkmark_stack_widget">Checkmark Stack Widget</string>
|
||||
<string name="frequency_stack_widget">Frequency Stack Widget</string>
|
||||
<string name="score_stack_widget">Score Stack Widget</string>
|
||||
<string name="history_stack_widget">History Stack Widget</string>
|
||||
<string name="streaks_stack_widget">Streaks Stack Widget</string>
|
||||
|
||||
|
||||
<string name="strength">Strength</string>
|
||||
<string name="best_streaks">Best streaks</string>
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
android:previewImage="@drawable/widget_preview_checkmark"
|
||||
android:resizeMode="none"
|
||||
android:updatePeriodMillis="3600000"
|
||||
android:configure="org.isoron.uhabits.widgets.HabitGroupPickerDialog"
|
||||
android:configure="org.isoron.uhabits.widgets.HabitPickerDialog"
|
||||
android:widgetCategory="home_screen">
|
||||
</appwidget-provider>
|
||||
@@ -21,11 +21,6 @@ package org.isoron.uhabits.core.preferences;
|
||||
|
||||
import org.isoron.uhabits.core.AppScope;
|
||||
import org.isoron.uhabits.core.models.HabitNotFoundException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -33,6 +28,9 @@ import javax.inject.Inject;
|
||||
public class WidgetPreferences {
|
||||
private Preferences.Storage storage;
|
||||
|
||||
public static final long STACK_WIDGET_HABITS = -1;
|
||||
public static final long HABIT_NOT_FOUND = -2;
|
||||
|
||||
@Inject
|
||||
public WidgetPreferences(Preferences.Storage storage) {
|
||||
this.storage = storage;
|
||||
@@ -42,32 +40,13 @@ public class WidgetPreferences {
|
||||
storage.putLong(getHabitIdKey(widgetId), habitId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param habitIds the string should be in the format: [habitId1, habitId2, habitId3...]
|
||||
*/
|
||||
public void addWidget(int widgetId, String habitIds) {
|
||||
storage.putString(getHabitIdKey(widgetId), habitIds);
|
||||
}
|
||||
|
||||
public long getHabitIdFromWidgetId(int widgetId) {
|
||||
Long habitId = storage.getLong(getHabitIdKey(widgetId), -1);
|
||||
if (habitId < 0) throw new HabitNotFoundException();
|
||||
Long habitId = storage.getLong(getHabitIdKey(widgetId), HABIT_NOT_FOUND);
|
||||
if (habitId == HABIT_NOT_FOUND) throw new HabitNotFoundException();
|
||||
|
||||
return habitId;
|
||||
}
|
||||
|
||||
public List<Long> getHabitIdsGroupFromWidgetId(int widgetId) {
|
||||
String habitIdsGroup = storage.getString(getHabitIdKey(widgetId), "");
|
||||
if (habitIdsGroup.isEmpty()) throw new HabitNotFoundException();
|
||||
|
||||
ArrayList<Long> habitIdList = new ArrayList<>();
|
||||
for (String s : parseStringToList(habitIdsGroup)) {
|
||||
habitIdList.add(Long.parseLong(s.trim()));
|
||||
}
|
||||
|
||||
return habitIdList;
|
||||
}
|
||||
|
||||
public void removeWidget(int id) {
|
||||
String habitIdKey = getHabitIdKey(id);
|
||||
storage.remove(habitIdKey);
|
||||
@@ -76,9 +55,4 @@ public class WidgetPreferences {
|
||||
private String getHabitIdKey(int id) {
|
||||
return String.format("widget-%06d-habit", id);
|
||||
}
|
||||
|
||||
private List<String> parseStringToList(@NotNull String str) {
|
||||
return Arrays.asList(str.replace("[", "")
|
||||
.replace("]", "").split(","));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user