Continue work on widgets

This commit is contained in:
Phillip Thelen 2016-09-12 21:11:35 +02:00
parent fc7ab5c319
commit 256d9e3ea9
19 changed files with 419 additions and 165 deletions

View file

@ -147,6 +147,11 @@
</intent-filter>
</receiver>
<activity android:name=".ui.activities.AddTaskWidgetActivity">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<service
android:name=".helpers.notifications.HabiticaFirebaseMessagingService">
@ -171,13 +176,22 @@
android:resource="@xml/filepaths" />
</provider>
<receiver android:name=".widget.AvatarStatsWidgetProvider" >
<receiver android:name=".widget.AvatarStatsWidgetProvider"
android:label="@string/stats_widget_label">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/avatar_widget_info" />
</receiver>
<receiver android:name=".widget.AddTaskWidgetProvider"
android:label="Habitica Add Task">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/add_task_widget_info" />
</receiver>
<service android:name=".widget.AvatarStatsWidgetService"/>
</application>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<!-- view background color -->
<solid
android:color="@color/neutral_10" >
</solid>
</shape>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<!-- view background color -->
<solid
android:color="@color/best_10" >
</solid>
</shape>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<!-- view background color -->
<solid
android:color="@color/brand_100" >
</solid>
</shape>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<!-- view background color -->
<solid
android:color="@color/worse_10" >
</solid>
</shape>

View file

@ -10,7 +10,7 @@
<!-- Here is the corner radius -->
<corners
android:radius="5dp" >
android:radius="2dp" >
</corners>
</shape>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<ImageView
android:id="@+id/add_task_icon"
android:layout_width="35dp"
android:layout_height="35dp"
android:src="@drawable/fab_add"
android:background="@drawable/widget_add_habit_background"
android:scaleType="center" />
<TextView
android:id="@+id/add_task_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_task"
android:layout_marginTop="4dp"
android:layout_gravity="center_horizontal"
android:textSize="12sp"
android:textColor="@android:color/white"
android:singleLine="false"
android:shadowColor="@android:color/black"
android:shadowRadius="2"
android:shadowDx="1"
android:shadowDy="1" />
</LinearLayout>

View file

@ -8,6 +8,7 @@
android:focusableInTouchMode="true"
android:background="@drawable/rounded_purple_square"
android:padding="8dp"
android:elevation="2dp"
android:orientation="vertical">
<LinearLayout
android:orientation="horizontal"

View file

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="16dp">
<LinearLayout
android:id="@+id/add_habit_button"
android:orientation="vertical" android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_weight="1">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/fab_add"
android:background="@drawable/widget_add_habit_background" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_habit"
android:layout_marginTop="2dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/add_daily_button"
android:orientation="vertical" android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_weight="1">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/fab_add"
android:background="@drawable/widget_add_daily_background" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_daily"
android:layout_marginTop="2dp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/add_todo_button"
android:orientation="vertical" android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_weight="1">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/fab_add"
android:background="@drawable/widget_add_todo_background" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_todo"
android:layout_marginTop="2dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/add_reward_button"
android:orientation="vertical" android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_weight="1">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/fab_add"
android:background="@drawable/widget_add_reward_background" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_reward"
android:layout_marginTop="2dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View file

@ -397,5 +397,11 @@ To start, which parts of your life do you want to improve?</string>
<string name="scan_qr_code">Scan QR Code</string>
<string name="enter_recipient_uuid">Enter Recipients User ID</string>
<string name="invited_to_party">You were invited to join a party!</string>
<string name="stats_widget_label">Habitica Stats</string>
<string name="add_task">Add Task</string>
<string name="add_habit">Add Habit</string>
<string name="add_daily">Add Daily</string>
<string name="add_todo">Add To-Do</string>
<string name="add_reward">Add Reward</string>
</resources>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/widget_add_task"
android:minHeight="40dp"
android:minWidth="40dp"
android:configure="com.habitrpg.android.habitica.ui.activities.AddTaskWidgetActivity">
</appwidget-provider>

View file

@ -0,0 +1,80 @@
package com.habitrpg.android.habitica.ui.activities;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.preference.PreferenceManager;
import android.util.Log;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.widget.AddTaskWidgetProvider;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class AddTaskWidgetActivity extends AppCompatActivity {
private int widgetId;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setResult(RESULT_CANCELED);
setContentView(R.layout.widget_configure_add_task);
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();
}
}
@OnClick(R.id.add_habit_button)
public void addHabitSelected() {
finishWithSelection(Task.TYPE_HABIT);
}
@OnClick(R.id.add_daily_button)
public void addDailySelected() {
finishWithSelection(Task.TYPE_DAILY);
}
@OnClick(R.id.add_todo_button)
public void addToDoSelected() {
finishWithSelection(Task.TYPE_TODO);
}
@OnClick(R.id.add_reward_button)
public void addRewardSelected() {
finishWithSelection(Task.TYPE_REWARD);
}
private void finishWithSelection(String selectedTaskType) {
storeSelectedTaskType(selectedTaskType);
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, AddTaskWidgetProvider.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {widgetId});
sendBroadcast(intent);
}
private void storeSelectedTaskType(String selectedTaskType) {
SharedPreferences.Editor preferences = PreferenceManager.getDefaultSharedPreferences(this).edit();
preferences.putString("add_task_widget_" + widgetId, selectedTaskType);
preferences.apply();
}
}

View file

@ -0,0 +1,74 @@
package com.habitrpg.android.habitica.widget;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.widget.RemoteViews;
import com.habitrpg.android.habitica.R;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
public class AddTaskWidgetProvider extends BaseWidgetProvider {
@Override
public int layoutResourceId() {
return R.layout.widget_add_task;
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// Get all ids
ComponentName thisWidget = new ComponentName(context,
AddTaskWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
if (Build.VERSION.SDK_INT >= 16) {
for (int widgetId : allWidgetIds) {
Bundle options = appWidgetManager.getAppWidgetOptions(widgetId);
appWidgetManager.partiallyUpdateAppWidget(widgetId,
sizeRemoteViews(context, options, widgetId));
}
}
}
@Override
public RemoteViews configureRemoteViews(RemoteViews remoteViews, int widgetId, int columns, int rows) {
String selectedTaskType = getSelectedTaskType(widgetId);
String addText = "";
int backgroundResource = R.drawable.widget_add_habit_background;
switch (selectedTaskType) {
case Task.TYPE_HABIT:
addText = this.context.getResources().getString(R.string.add_habit);
backgroundResource = R.drawable.widget_add_habit_background;
break;
case Task.TYPE_DAILY:
addText = this.context.getResources().getString(R.string.add_daily);
backgroundResource = R.drawable.widget_add_daily_background;
break;
case Task.TYPE_TODO:
addText = this.context.getResources().getString(R.string.add_todo);
backgroundResource = R.drawable.widget_add_todo_background;
break;
case Task.TYPE_REWARD:
addText = this.context.getResources().getString(R.string.add_reward);
backgroundResource = R.drawable.widget_add_reward_background;
break;
}
remoteViews.setTextViewText(R.id.add_task_text, addText);
remoteViews.setInt(R.id.add_task_icon, "setBackgroundResource", backgroundResource);
return remoteViews;
}
private String getSelectedTaskType(int widgetId) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this.context);
return preferences.getString("add_task_widget_"+widgetId, Task.TYPE_HABIT);
}
}

View file

@ -14,22 +14,12 @@ import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
public class AvatarStatsWidgetProvider extends AppWidgetProvider {
public class AvatarStatsWidgetProvider extends BaseWidgetProvider {
private static final String LOG = AvatarStatsWidgetProvider.class.getName();
/**
* Returns number of cells needed for given size of the widget.<br/>
* see http://stackoverflow.com/questions/14270138/dynamically-adjusting-widgets-content-and-layout-to-the-size-the-user-defined-t
*
* @param size Widget size in dp.
* @return Size in number of cells.
*/
private static int getCellsForSize(int size) {
int n = 2;
while (70 * n - 30 < size) {
++n;
}
return n - 1;
@Override
public int layoutResourceId() {
return R.layout.widget_avatar_stats;
}
@Override
@ -43,7 +33,7 @@ public class AvatarStatsWidgetProvider extends AppWidgetProvider {
for (int widgetId : allWidgetIds) {
Bundle options = appWidgetManager.getAppWidgetOptions(widgetId);
appWidgetManager.partiallyUpdateAppWidget(widgetId,
configureRemoteViews(context, options));
sizeRemoteViews(context, options, widgetId));
}
}
@ -55,36 +45,9 @@ public class AvatarStatsWidgetProvider extends AppWidgetProvider {
context.startService(intent);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
appWidgetManager.partiallyUpdateAppWidget(appWidgetId,
configureRemoteViews(context, options));
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId,
newOptions);
}
/**
* Determine appropriate view based on width provided.<br/>
* see http://stackoverflow.com/questions/14270138/dynamically-adjusting-widgets-content-and-layout-to-the-size-the-user-defined-t
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private RemoteViews configureRemoteViews(Context context, Bundle options) {
int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int minHeight = options
.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
// First find out rows and columns based on width provided.
int rows = getCellsForSize(minHeight);
int columns = getCellsForSize(minWidth);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_avatar_stats);
public RemoteViews configureRemoteViews(RemoteViews remoteViews, int widgetId, int columns, int rows) {
if (columns > 3) {
remoteViews.setViewVisibility(R.id.avatar_view, View.VISIBLE);
} else {
@ -100,6 +63,5 @@ public class AvatarStatsWidgetProvider extends AppWidgetProvider {
}
return remoteViews;
}
}

View file

@ -27,12 +27,6 @@ import android.widget.RemoteViews;
import javax.inject.Inject;
/**
* The service that should update the simple widget
*
* @see com.habitrpg.android.habitica.widget.SimpleWidget
* Created by Mickael on 01/11/13.
*/
public class AvatarStatsWidgetService extends Service {
private static final String LOG = ".avatarwidget.service";
@Inject
@ -102,11 +96,9 @@ public class AvatarStatsWidgetService extends Service {
AvatarView avatarView = new AvatarView(this, true, true, true);;
avatarView.setUser(user);
avatarView.onAvatarImageReady(bitmap -> {
Log.e("AVATAR BITMAP", bitmap.toString());
remoteViews.setImageViewBitmap(R.id.avatar_view, bitmap);
remoteViews.setImageViewBitmap(R.id.avatar_view, bitmap);
appWidgetManager.partiallyUpdateAppWidget(allWidgetIds, remoteViews);
});
Log.e("AVATAR THING", "BLA");
//If user click on life and xp: open the app
Intent openAppIntent = new Intent(this.getApplicationContext(), MainActivity.class);

View file

@ -0,0 +1,66 @@
package com.habitrpg.android.habitica.widget;
import android.annotation.TargetApi;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.RemoteViews;
import com.habitrpg.android.habitica.R;
public abstract class BaseWidgetProvider extends AppWidgetProvider {
protected Context context;
/**
* Returns number of cells needed for given size of the widget.<br/>
* see http://stackoverflow.com/questions/14270138/dynamically-adjusting-widgets-content-and-layout-to-the-size-the-user-defined-t
*
* @param size Widget size in dp.
* @return Size in number of cells.
*/
private static int getCellsForSize(int size) {
int n = 2;
while (70 * n - 30 < size) {
++n;
}
return n - 1;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
this.context = context;
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
appWidgetManager.partiallyUpdateAppWidget(appWidgetId,
sizeRemoteViews(context, options, appWidgetId));
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId,
newOptions);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public RemoteViews sizeRemoteViews(Context context, Bundle options, int widgetId) {
this.context = context;
int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int minHeight = options
.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
// First find out rows and columns based on width provided.
int rows = getCellsForSize(minHeight);
int columns = getCellsForSize(minWidth);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
layoutResourceId());
return configureRemoteViews(remoteViews, widgetId, columns, rows);
}
abstract public int layoutResourceId();
abstract public RemoteViews configureRemoteViews(RemoteViews remoteViews, int widgetId, int columns, int rows);
}

View file

@ -1,105 +0,0 @@
package com.habitrpg.android.habitica.widget;
import com.habitrpg.android.habitica.R;
import android.annotation.TargetApi;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
/**
* Define a simple custom widget for the habitrpg client
* Created by Mickael on 31/10/13.
*/
public class SimpleWidget extends AppWidgetProvider {
private static final String LOG = "simplewidgetprovider";
/**
* Returns number of cells needed for given size of the widget.<br/>
* see http://stackoverflow.com/questions/14270138/dynamically-adjusting-widgets-content-and-layout-to-the-size-the-user-defined-t
*
* @param size Widget size in dp.
* @return Size in number of cells.
*/
private static int getCellsForSize(int size) {
int n = 2;
while (70 * n - 30 < size) {
++n;
}
return n - 1;
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Log.w(LOG, "onUpdate method called");
// Get all ids
ComponentName thisWidget = new ComponentName(context,
SimpleWidget.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
if (Build.VERSION.SDK_INT >= 16) {
for (int widgetId : allWidgetIds) {
Bundle options = appWidgetManager.getAppWidgetOptions(widgetId);
appWidgetManager.updateAppWidget(widgetId,
getRemoteViews(context, options));
}
}
// Build the intent to call the service
Intent intent = new Intent(context.getApplicationContext(),
AvatarStatsWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
// Update the widgets via the service
context.startService(intent);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
Log.v(LOG, "onAppWidgetOptionChanged call");
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
appWidgetManager.updateAppWidget(appWidgetId,
getRemoteViews(context, options));
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId,
newOptions);
}
/**
* Determine appropriate view based on width provided.<br/>
* see http://stackoverflow.com/questions/14270138/dynamically-adjusting-widgets-content-and-layout-to-the-size-the-user-defined-t
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private RemoteViews getRemoteViews(Context context, Bundle options) {
int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int minHeight = options
.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
// First find out rows and columns based on width provided.
int rows = getCellsForSize(minHeight);
int columns = getCellsForSize(minWidth);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.simple_widget);
if (columns > 2) {
remoteViews.setViewVisibility(R.id.LL_header, View.VISIBLE);
// Get 4 column widget remote view and return
} else {
remoteViews.setViewVisibility(R.id.LL_header, View.GONE);
}
return remoteViews;
}
}

View file

@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.android.tools.build:gradle:2.1.3'
classpath 'com.android.databinding:dataBinder:1.0-rc4'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.google.gms:google-services:3.0.0'

View file

@ -1,7 +1,7 @@
#Wed Apr 27 08:20:39 CST 2016
#Mon Sep 12 12:48:06 CEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
org.gradle.jvmargs=-Xmx3072M
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip