mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Implemented ability to choose multiple habits for stackview
This commit is contained in:
@@ -84,6 +84,13 @@
|
||||
<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">
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,11 @@ import android.content.Intent
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.widgets.views.CheckmarkWidgetView
|
||||
|
||||
class StackGroupWidget(
|
||||
context: Context,
|
||||
widgetId: Int
|
||||
widgetId: Int,
|
||||
private val habitIds: List<Long>
|
||||
) : BaseWidget(context, widgetId) {
|
||||
|
||||
override fun getOnClickPendingIntent(context: Context) = null
|
||||
@@ -42,8 +42,7 @@ class StackGroupWidget(
|
||||
val remoteViews = RemoteViews(context.packageName, R.layout.widget_stackview)
|
||||
val serviceIntent = Intent(context, StackWidgetService::class.java)
|
||||
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id)
|
||||
// TODO this commented line is taken from official examples, but adding it seems to make the widget not update immediately when completing the habit
|
||||
// serviceIntent.data = Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)) // embed extras so they don't get ignored
|
||||
serviceIntent.putExtra(StackWidgetService.HABIT_IDS_SELECTED, habitIds.toLongArray())
|
||||
remoteViews.setRemoteAdapter(R.id.stackWidgetView, serviceIntent)
|
||||
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(id, R.id.stackWidgetView)
|
||||
// TODO what should the empty view look like?
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package org.isoron.uhabits.widgets
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import org.isoron.uhabits.R
|
||||
|
||||
/**
|
||||
* Created by victoryu on 9/30/17.
|
||||
*/
|
||||
import org.isoron.uhabits.HabitsApplication
|
||||
|
||||
class StackWidgetProvider : BaseWidgetProvider() {
|
||||
|
||||
override fun getWidgetFromId(context: Context, id: Int): StackGroupWidget {
|
||||
return StackGroupWidget(context, id)
|
||||
val habitIds = getHabitGroupFromWidget(context, id)
|
||||
return StackGroupWidget(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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,19 +12,19 @@ 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;
|
||||
|
||||
/**
|
||||
* Created by victoryu on 9/30/17.
|
||||
*/
|
||||
import static org.isoron.uhabits.widgets.StackWidgetService.HABIT_IDS_SELECTED;
|
||||
|
||||
public class StackWidgetService extends RemoteViewsService {
|
||||
|
||||
public static final String HABIT_IDS_SELECTED = "HABIT_IDS_SELECTED";
|
||||
|
||||
@Override
|
||||
public RemoteViewsFactory onGetViewFactory(Intent intent) {
|
||||
return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
|
||||
@@ -35,10 +35,15 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
|
||||
private Context mContext;
|
||||
private int mAppWidgetId;
|
||||
private ArrayList<Habit> mHabitList;
|
||||
private List<Long> mHabitsSelected;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public void onCreate() {
|
||||
@@ -104,7 +109,9 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
|
||||
mHabitList = new ArrayList<>();
|
||||
HabitsApplication app = (HabitsApplication) mContext.getApplicationContext();
|
||||
for (Habit h : app.getComponent().getHabitList()) {
|
||||
mHabitList.add(h);
|
||||
if (mHabitsSelected.contains(h.getId())) {
|
||||
mHabitList.add(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/listItemHabitName"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/listItemHabitCheckbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="false" />
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/stackWidgetListView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1" >
|
||||
|
||||
</ListView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/doneConfigureButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/done_label" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -112,6 +112,7 @@
|
||||
<string name="clear_label">Clear</string>
|
||||
<string name="select_hours">Select hours</string>
|
||||
<string name="select_minutes">Select minutes</string>
|
||||
<string name="select_habit_requirement_prompt">Please select at least one habit</string>
|
||||
|
||||
<string-array name="hints">
|
||||
<item>@string/hint_drag</item>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
android:previewImage="@drawable/widget_preview_checkmark"
|
||||
android:resizeMode="none"
|
||||
android:updatePeriodMillis="3600000"
|
||||
android:configure="org.isoron.uhabits.widgets.HabitPickerDialog"
|
||||
android:configure="org.isoron.uhabits.widgets.HabitGroupPickerDialog"
|
||||
android:widgetCategory="home_screen">
|
||||
|
||||
</appwidget-provider>
|
||||
Reference in New Issue
Block a user