diff --git a/Habitica/AndroidManifest.xml b/Habitica/AndroidManifest.xml
index c195eccc7..effee908c 100644
--- a/Habitica/AndroidManifest.xml
+++ b/Habitica/AndroidManifest.xml
@@ -152,6 +152,11 @@
+
+
+
+
+
@@ -185,7 +190,7 @@
android:resource="@xml/avatar_widget_info" />
+ android:label="@string/widget_add_task">
@@ -193,17 +198,26 @@
android:resource="@xml/add_task_widget_info" />
+ android:label="@string/widget_dailies">
+
+
+
+
+
+
+
diff --git a/Habitica/res/drawable/widget_background.xml b/Habitica/res/drawable/widget_background.xml
index ec645c0a6..d20a9e9e3 100644
--- a/Habitica/res/drawable/widget_background.xml
+++ b/Habitica/res/drawable/widget_background.xml
@@ -10,7 +10,7 @@
+ android:radius="@dimen/widget_rounding" >
\ No newline at end of file
diff --git a/Habitica/res/layout/widget_configure_habit_button.xml b/Habitica/res/layout/widget_configure_habit_button.xml
new file mode 100644
index 000000000..52a5f6d8e
--- /dev/null
+++ b/Habitica/res/layout/widget_configure_habit_button.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/layout/widget_habit_button.xml b/Habitica/res/layout/widget_habit_button.xml
new file mode 100644
index 000000000..9cfedc0f5
--- /dev/null
+++ b/Habitica/res/layout/widget_habit_button.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/values/dimens.xml b/Habitica/res/values/dimens.xml
index fa1c3e7d4..ab1a042a3 100644
--- a/Habitica/res/values/dimens.xml
+++ b/Habitica/res/values/dimens.xml
@@ -83,4 +83,5 @@
7dp
40dp
13dp
+ 5dp
\ No newline at end of file
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 31f0a8177..406b3d6b5 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -404,5 +404,8 @@ To start, which parts of your life do you want to improve?
Add To-Do
Add Reward
You completed all your dailies. Well done!
+ Habitica Do Habit
+ Habitica Dailies
+ Habitica Add Task
diff --git a/Habitica/res/xml/habit_button_widget_info.xml b/Habitica/res/xml/habit_button_widget_info.xml
new file mode 100644
index 000000000..2b4a832e2
--- /dev/null
+++ b/Habitica/res/xml/habit_button_widget_info.xml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java b/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
index 2802a5da2..69feea14e 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
@@ -9,6 +9,7 @@ import com.habitrpg.android.habitica.ui.activities.AboutActivity;
import com.habitrpg.android.habitica.ui.activities.ClassSelectionActivity;
import com.habitrpg.android.habitica.ui.activities.FullProfileActivity;
import com.habitrpg.android.habitica.ui.activities.GroupFormActivity;
+import com.habitrpg.android.habitica.ui.activities.HabitButtonWidgetActivity;
import com.habitrpg.android.habitica.ui.activities.IntroActivity;
import com.habitrpg.android.habitica.ui.activities.LoginActivity;
import com.habitrpg.android.habitica.ui.activities.MainActivity;
@@ -55,6 +56,7 @@ import com.habitrpg.android.habitica.ui.fragments.tasks.TaskRecyclerViewFragment
import com.habitrpg.android.habitica.ui.fragments.tasks.TasksFragment;
import com.habitrpg.android.habitica.widget.AvatarStatsWidgetService;
import com.habitrpg.android.habitica.widget.DailiesWidgetProvider;
+import com.habitrpg.android.habitica.widget.HabitButtonWidgetService;
import javax.inject.Singleton;
@@ -168,4 +170,8 @@ public interface AppComponent {
void inject(FullProfileActivity fullProfileActivity);
void inject(DailiesWidgetProvider dailiesWidgetProvider);
+
+ void inject(HabitButtonWidgetService habitButtonWidgetService);
+
+ void inject(HabitButtonWidgetActivity habitButtonWidgetActivity);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java
index d4cdf28f3..ce5bda5e2 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java
@@ -7,6 +7,7 @@ import com.habitrpg.android.habitica.helpers.TagsHelper;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.Resources;
import android.support.v7.preference.PreferenceManager;
import javax.inject.Named;
@@ -47,4 +48,9 @@ public class AppModule {
public TagsHelper providesTagsHelper() {
return new TagsHelper();
}
+
+ @Provides
+ public Resources providesResources(Context context) {
+ return context.getResources();
+ }
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.java
new file mode 100644
index 000000000..aa9e15aa2
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.java
@@ -0,0 +1,89 @@
+package com.habitrpg.android.habitica.ui.activities;
+
+import android.app.Activity;
+import android.appwidget.AppWidgetManager;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.components.AppComponent;
+import com.habitrpg.android.habitica.ui.adapter.SkillTasksRecyclerViewAdapter;
+import com.habitrpg.android.habitica.widget.AddTaskWidgetProvider;
+import com.habitrpg.android.habitica.widget.HabitButtonWidgetProvider;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+
+public class HabitButtonWidgetActivity extends BaseActivity implements TaskClickActivity {
+
+ @BindView(R.id.recyclerView)
+ RecyclerView recyclerView;
+ private int widgetId;
+
+ @Override
+ protected int getLayoutResId() {
+ return R.layout.widget_configure_habit_button;
+ }
+
+ @Override
+ protected void injectActivity(AppComponent component) {
+ component.inject(this);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ButterKnife.bind(this);
+
+ Intent intent = getIntent();
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
+ }
+
+ // If this activity was started with an intent without an app widget ID,
+ // finish with an error.
+ if (widgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+ finish();
+ }
+
+ LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
+
+ if (layoutManager == null) {
+ layoutManager = new LinearLayoutManager(this);
+
+ recyclerView.setLayoutManager(layoutManager);
+ }
+
+ recyclerView.setAdapter(new SkillTasksRecyclerViewAdapter(Task.TYPE_HABIT, this));
+ }
+
+ @Override
+ public void taskSelected(String taskId) {
+ finishWithSelection(taskId);
+ }
+
+ private void finishWithSelection(String selectedTaskId) {
+ storeSelectedTaskId(selectedTaskId);
+
+ Intent resultValue = new Intent();
+ resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
+ setResult(RESULT_OK, resultValue);
+ finish();
+
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, this, HabitButtonWidgetProvider.class);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {widgetId});
+ sendBroadcast(intent);
+ }
+
+ private void storeSelectedTaskId(String selectedTaskId) {
+ SharedPreferences.Editor preferences = PreferenceManager.getDefaultSharedPreferences(this).edit();
+ preferences.putString("habit_button_widget_" + widgetId, selectedTaskId);
+ preferences.apply();
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.java
index 7b7d14cca..0ce5604e2 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.java
@@ -20,7 +20,7 @@ import java.util.Map;
import butterknife.BindView;
-public class SkillTasksActivity extends BaseActivity {
+public class SkillTasksActivity extends BaseActivity implements TaskClickActivity {
@BindView(R.id.viewpager)
public ViewPager viewPager;
@@ -100,3 +100,4 @@ public class SkillTasksActivity extends BaseActivity {
finish();
}
}
+
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskClickActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskClickActivity.java
new file mode 100644
index 000000000..59fdd2f44
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskClickActivity.java
@@ -0,0 +1,5 @@
+package com.habitrpg.android.habitica.ui.activities;
+
+public interface TaskClickActivity {
+ void taskSelected(String taskId);
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillTasksRecyclerViewAdapter.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillTasksRecyclerViewAdapter.java
index e0b028346..3ad69abf5 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillTasksRecyclerViewAdapter.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillTasksRecyclerViewAdapter.java
@@ -3,6 +3,7 @@ package com.habitrpg.android.habitica.ui.adapter;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.databinding.SkillTaskItemCardBinding;
import com.habitrpg.android.habitica.ui.activities.SkillTasksActivity;
+import com.habitrpg.android.habitica.ui.activities.TaskClickActivity;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
import com.raizlabs.android.dbflow.sql.builder.Condition;
import com.raizlabs.android.dbflow.sql.language.OrderBy;
@@ -28,11 +29,11 @@ public class SkillTasksRecyclerViewAdapter extends RecyclerView.Adapter observableContent;
private RecyclerView.Adapter parentAdapter;
- public SkillTasksRecyclerViewAdapter(String taskType, SkillTasksActivity activity) {
+ public SkillTasksRecyclerViewAdapter(String taskType, TaskClickActivity activity) {
this.setHasStableIds(true);
this.taskType = taskType;
this.activity = activity;
@@ -129,7 +130,7 @@ public class SkillTasksRecyclerViewAdapter extends RecyclerView.Adapter= 16) {
+ for (int widgetId : allWidgetIds) {
+ Bundle options = appWidgetManager.getAppWidgetOptions(widgetId);
+ appWidgetManager.partiallyUpdateAppWidget(widgetId,
+ sizeRemoteViews(context, options, widgetId));
+ }
+ }
+
+ // Build the intent to call the service
+ Intent intent = new Intent(context.getApplicationContext(),
+ HabitButtonWidgetService.class);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
+
+ context.startService(intent);
+ }
+
+ @Override
+ public RemoteViews configureRemoteViews(RemoteViews remoteViews, int widgetId, int columns, int rows) {
+ return remoteViews;
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java
new file mode 100644
index 000000000..abed585ed
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java
@@ -0,0 +1,117 @@
+package com.habitrpg.android.habitica.widget;
+
+import android.app.Service;
+import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.os.IBinder;
+import android.preference.PreferenceManager;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import com.habitrpg.android.habitica.HabiticaApplication;
+import com.habitrpg.android.habitica.HostConfig;
+import com.habitrpg.android.habitica.R;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
+import com.raizlabs.android.dbflow.runtime.transaction.BaseTransaction;
+import com.raizlabs.android.dbflow.runtime.transaction.TransactionListener;
+import com.raizlabs.android.dbflow.sql.builder.Condition;
+import com.raizlabs.android.dbflow.sql.language.Select;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+public class HabitButtonWidgetService extends Service {
+ @Inject
+ public HostConfig hostConfig;
+ @Inject
+ public SharedPreferences sharedPreferences;
+ @Inject
+ public Resources resources;
+ private AppWidgetManager appWidgetManager;
+
+ private Map taskMapping;
+
+ @Override
+ public int onStartCommand(final Intent intent, int flags, int startId) {
+ HabiticaApplication application = (HabiticaApplication) getApplication();
+ application.getComponent().inject(this);
+ this.appWidgetManager = AppWidgetManager.getInstance(this);
+
+ makeTaskMapping();
+
+ for (String taskid : this.taskMapping.keySet()) {
+ new Select().from(Task.class).where(Condition.column("id").eq(taskid)).async().querySingle(userTransactionListener);
+ }
+
+ stopSelf();
+
+ return START_STICKY;
+ }
+
+ private TransactionListener userTransactionListener = new TransactionListener() {
+ @Override
+ public void onResultReceived(Task task) {
+ updateData(task);
+ }
+
+ @Override
+ public boolean onReady(BaseTransaction task) {
+ return true;
+ }
+
+ @Override
+ public boolean hasResult(BaseTransaction baseTransaction, Task task) {
+ return true;
+ }
+ };
+
+ private void updateData(Task task) {
+ RemoteViews remoteViews = new RemoteViews(this.getPackageName(), R.layout.widget_habit_button);
+ remoteViews.setTextViewText(R.id.habit_title, task.text);
+
+ if (!task.getUp()) {
+ remoteViews.setViewVisibility(R.id.btnPlusWrapper, View.GONE);
+ } else {
+ remoteViews.setViewVisibility(R.id.btnPlusWrapper, View.VISIBLE);
+
+ remoteViews.setInt(R.id.btnPlus, "setBackgroundColor", resources.getColor(task.getLightTaskColor()));
+ }
+ if (!task.getDown()) {
+ remoteViews.setViewVisibility(R.id.btnMinusWrapper, View.GONE);
+ } else {
+ remoteViews.setViewVisibility(R.id.btnMinusWrapper, View.VISIBLE);
+ remoteViews.setInt(R.id.btnMinus, "setBackgroundColor", resources.getColor(task.getMediumTaskColor()));
+ }
+
+ appWidgetManager.partiallyUpdateAppWidget(taskMapping.get(task.getId()), remoteViews);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ private void makeTaskMapping() {
+ ComponentName thisWidget = new ComponentName(this, HabitButtonWidgetProvider.class);
+ int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
+ this.taskMapping = new HashMap<>();
+ for (int widgetId : allWidgetIds) {
+ String taskId = getTaskId(widgetId);
+ if (!taskId.equals("")) {
+ this.taskMapping.put(taskId, widgetId);
+ }
+ }
+ }
+
+ private String getTaskId(int widgetId) {
+ return sharedPreferences.getString("habit_button_widget_"+widgetId, "");
+ }
+}