Code review changes; Made 'stack view' design available for all widgets

pull/346/head
Victor Yu 8 years ago
parent 268cb0bc18
commit 8feb07ff1b

@ -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(","));
}
}

Loading…
Cancel
Save