mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Merge branch 'widgets' into dev
This commit is contained in:
@@ -10,11 +10,11 @@
|
|||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="com.activeandroid.app.Application"
|
android:name="com.activeandroid.app.Application"
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:backupAgent=".HabitsBackupAgent"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/main_activity_title"
|
android:label="@string/main_activity_title"
|
||||||
android:theme="@style/AppBaseTheme"
|
android:theme="@style/AppBaseTheme">
|
||||||
android:allowBackup="true"
|
|
||||||
android:backupAgent=".HabitsBackupAgent">
|
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="AA_DB_NAME"
|
android:name="AA_DB_NAME"
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.backup.api_key"
|
android:name="com.google.android.backup.api_key"
|
||||||
android:value="AEdPqrEAAAAI6aeWncbnMNo8E5GWeZ44dlc5cQ7tCROwFhOtiw" />
|
android:value="AEdPqrEAAAAI6aeWncbnMNo8E5GWeZ44dlc5cQ7tCROwFhOtiw"/>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".ReminderAlarmReceiver" />
|
android:name=".HabitBroadcastReceiver"/>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ShowHabitActivity"
|
android:name=".ShowHabitActivity"
|
||||||
@@ -59,9 +59,65 @@
|
|||||||
android:value="org.isoron.uhabits.MainActivity"/>
|
android:value="org.isoron.uhabits.MainActivity"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".IntroActivity"
|
<activity
|
||||||
android:label=""
|
android:name=".IntroActivity"
|
||||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
|
android:label=""
|
||||||
|
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".widgets.CheckmarkWidgetProvider"
|
||||||
|
android:label="Checkmark">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/widget_checkmark_info"/>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".widgets.HistoryWidgetProvider"
|
||||||
|
android:label="History">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/widget_history_info"/>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".widgets.ScoreWidgetProvider"
|
||||||
|
android:label="Score">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/widget_score_info"/>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".widgets.StreakWidgetProvider"
|
||||||
|
android:label="Streaks">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/widget_streak_info"/>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".widgets.HabitPickerDialog"
|
||||||
|
android:theme="@style/Theme.AppCompat.Light.Dialog">
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
</activity>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
BIN
app/src/main/ic_small_widget_preview-web.png
Normal file
BIN
app/src/main/ic_small_widget_preview-web.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -18,10 +18,12 @@ package org.isoron.helpers;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
@@ -72,4 +74,11 @@ public abstract class DialogHelper
|
|||||||
else
|
else
|
||||||
return attrs.getAttributeValue(ISORON_NAMESPACE, name);
|
return attrs.getAttributeValue(ISORON_NAMESPACE, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float dpToPixels(Context context, float dp)
|
||||||
|
{
|
||||||
|
Resources resources = context.getResources();
|
||||||
|
DisplayMetrics metrics = resources.getDisplayMetrics();
|
||||||
|
return dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.net.Uri;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
|
|
||||||
import org.isoron.helpers.DateHelper;
|
import org.isoron.helpers.DateHelper;
|
||||||
import org.isoron.uhabits.helpers.ReminderHelper;
|
import org.isoron.uhabits.helpers.ReminderHelper;
|
||||||
@@ -38,12 +39,11 @@ import org.isoron.uhabits.models.Habit;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class ReminderAlarmReceiver extends BroadcastReceiver
|
public class HabitBroadcastReceiver extends BroadcastReceiver
|
||||||
{
|
{
|
||||||
public static final String ACTION_CHECK = "org.isoron.uhabits.ACTION_CHECK";
|
public static final String ACTION_CHECK = "org.isoron.uhabits.ACTION_CHECK";
|
||||||
public static final String ACTION_DISMISS = "org.isoron.uhabits.ACTION_DISMISS";
|
public static final String ACTION_DISMISS = "org.isoron.uhabits.ACTION_DISMISS";
|
||||||
public static final String ACTION_REMIND = "org.isoron.uhabits.ACTION_REMIND";
|
public static final String ACTION_SHOW_REMINDER = "org.isoron.uhabits.ACTION_SHOW_REMINDER";
|
||||||
public static final String ACTION_REMOVE_REMINDER = "org.isoron.uhabits.ACTION_REMOVE_REMINDER";
|
|
||||||
public static final String ACTION_SNOOZE = "org.isoron.uhabits.ACTION_SNOOZE";
|
public static final String ACTION_SNOOZE = "org.isoron.uhabits.ACTION_SNOOZE";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -51,7 +51,7 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
|
|||||||
{
|
{
|
||||||
switch (intent.getAction())
|
switch (intent.getAction())
|
||||||
{
|
{
|
||||||
case ACTION_REMIND:
|
case ACTION_SHOW_REMINDER:
|
||||||
createNotification(context, intent);
|
createNotification(context, intent);
|
||||||
createReminderAlarms(context);
|
createReminderAlarms(context);
|
||||||
break;
|
break;
|
||||||
@@ -103,6 +103,12 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
|
|||||||
habit.toggleRepetition(timestamp);
|
habit.toggleRepetition(timestamp);
|
||||||
habit.save();
|
habit.save();
|
||||||
dismissNotification(context, habit);
|
dismissNotification(context, habit);
|
||||||
|
|
||||||
|
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(context);
|
||||||
|
Intent refreshIntent = new Intent(MainActivity.ACTION_REFRESH);
|
||||||
|
manager.sendBroadcast(refreshIntent);
|
||||||
|
|
||||||
|
MainActivity.updateWidgets(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dismissAllHabits()
|
private void dismissAllHabits()
|
||||||
@@ -146,21 +152,9 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
|
|||||||
PendingIntent contentPendingIntent =
|
PendingIntent contentPendingIntent =
|
||||||
PendingIntent.getActivity(context, 0, contentIntent, 0);
|
PendingIntent.getActivity(context, 0, contentIntent, 0);
|
||||||
|
|
||||||
Intent deleteIntent = new Intent(context, ReminderAlarmReceiver.class);
|
PendingIntent dismissPendingIntent = buildDismissIntent(context);
|
||||||
deleteIntent.setAction(ACTION_DISMISS);
|
PendingIntent checkIntentPending = buildCheckIntent(context, habit, timestamp);
|
||||||
PendingIntent deletePendingIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0);
|
PendingIntent snoozeIntentPending = buildSnoozeIntent(context, habit);
|
||||||
|
|
||||||
Intent checkIntent = new Intent(context, ReminderAlarmReceiver.class);
|
|
||||||
checkIntent.setData(data);
|
|
||||||
checkIntent.setAction(ACTION_CHECK);
|
|
||||||
checkIntent.putExtra("timestamp", timestamp);
|
|
||||||
PendingIntent checkIntentPending =
|
|
||||||
PendingIntent.getBroadcast(context, 0, checkIntent, PendingIntent.FLAG_ONE_SHOT);
|
|
||||||
|
|
||||||
Intent snoozeIntent = new Intent(context, ReminderAlarmReceiver.class);
|
|
||||||
snoozeIntent.setData(data);
|
|
||||||
snoozeIntent.setAction(ACTION_SNOOZE);
|
|
||||||
PendingIntent snoozeIntentPending = PendingIntent.getBroadcast(context, 0, snoozeIntent, 0);
|
|
||||||
|
|
||||||
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
|
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
|
||||||
|
|
||||||
@@ -173,7 +167,7 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
|
|||||||
.setContentTitle(habit.name)
|
.setContentTitle(habit.name)
|
||||||
.setContentText(habit.description)
|
.setContentText(habit.description)
|
||||||
.setContentIntent(contentPendingIntent)
|
.setContentIntent(contentPendingIntent)
|
||||||
.setDeleteIntent(deletePendingIntent)
|
.setDeleteIntent(dismissPendingIntent)
|
||||||
.addAction(R.drawable.ic_action_check,
|
.addAction(R.drawable.ic_action_check,
|
||||||
context.getString(R.string.check), checkIntentPending)
|
context.getString(R.string.check), checkIntentPending)
|
||||||
.addAction(R.drawable.ic_action_snooze,
|
.addAction(R.drawable.ic_action_snooze,
|
||||||
@@ -193,6 +187,32 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
|
|||||||
notificationManager.notify(notificationId, notification);
|
notificationManager.notify(notificationId, notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PendingIntent buildSnoozeIntent(Context context, Habit habit)
|
||||||
|
{
|
||||||
|
Uri data = habit.getUri();
|
||||||
|
Intent snoozeIntent = new Intent(context, HabitBroadcastReceiver.class);
|
||||||
|
snoozeIntent.setData(data);
|
||||||
|
snoozeIntent.setAction(ACTION_SNOOZE);
|
||||||
|
return PendingIntent.getBroadcast(context, 0, snoozeIntent, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PendingIntent buildCheckIntent(Context context, Habit habit, Long timestamp)
|
||||||
|
{
|
||||||
|
Uri data = habit.getUri();
|
||||||
|
Intent checkIntent = new Intent(context, HabitBroadcastReceiver.class);
|
||||||
|
checkIntent.setData(data);
|
||||||
|
checkIntent.setAction(ACTION_CHECK);
|
||||||
|
if(timestamp != null) checkIntent.putExtra("timestamp", timestamp);
|
||||||
|
return PendingIntent.getBroadcast(context, 0, checkIntent, PendingIntent.FLAG_ONE_SHOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PendingIntent buildDismissIntent(Context context)
|
||||||
|
{
|
||||||
|
Intent deleteIntent = new Intent(context, HabitBroadcastReceiver.class);
|
||||||
|
deleteIntent.setAction(ACTION_DISMISS);
|
||||||
|
return PendingIntent.getBroadcast(context, 0, deleteIntent, 0);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkWeekday(Intent intent, Habit habit)
|
private boolean checkWeekday(Intent intent, Habit habit)
|
||||||
{
|
{
|
||||||
Long timestamp = intent.getLongExtra("timestamp", DateHelper.getStartOfToday());
|
Long timestamp = intent.getLongExtra("timestamp", DateHelper.getStartOfToday());
|
||||||
@@ -16,11 +16,17 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits;
|
package org.isoron.uhabits;
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetManager;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
@@ -30,12 +36,21 @@ import org.isoron.helpers.ReplayableActivity;
|
|||||||
import org.isoron.uhabits.fragments.ListHabitsFragment;
|
import org.isoron.uhabits.fragments.ListHabitsFragment;
|
||||||
import org.isoron.uhabits.helpers.ReminderHelper;
|
import org.isoron.uhabits.helpers.ReminderHelper;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
import org.isoron.uhabits.widgets.BaseWidgetProvider;
|
||||||
|
import org.isoron.uhabits.widgets.CheckmarkWidgetProvider;
|
||||||
|
import org.isoron.uhabits.widgets.HistoryWidgetProvider;
|
||||||
|
import org.isoron.uhabits.widgets.ScoreWidgetProvider;
|
||||||
|
import org.isoron.uhabits.widgets.StreakWidgetProvider;
|
||||||
|
|
||||||
public class MainActivity extends ReplayableActivity
|
public class MainActivity extends ReplayableActivity
|
||||||
implements ListHabitsFragment.OnHabitClickListener
|
implements ListHabitsFragment.OnHabitClickListener
|
||||||
{
|
{
|
||||||
private ListHabitsFragment listHabitsFragment;
|
private ListHabitsFragment listHabitsFragment;
|
||||||
SharedPreferences prefs;
|
private SharedPreferences prefs;
|
||||||
|
private BroadcastReceiver receiver;
|
||||||
|
private LocalBroadcastManager localBroadcastManager;
|
||||||
|
|
||||||
|
public static final String ACTION_REFRESH = "org.isoron.uhabits.ACTION_REFRESH";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
@@ -47,6 +62,10 @@ public class MainActivity extends ReplayableActivity
|
|||||||
listHabitsFragment =
|
listHabitsFragment =
|
||||||
(ListHabitsFragment) getFragmentManager().findFragmentById(R.id.fragment1);
|
(ListHabitsFragment) getFragmentManager().findFragmentById(R.id.fragment1);
|
||||||
|
|
||||||
|
receiver = new Receiver();
|
||||||
|
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
||||||
|
localBroadcastManager.registerReceiver(receiver, new IntentFilter(ACTION_REFRESH));
|
||||||
|
|
||||||
onStartup();
|
onStartup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,6 +75,7 @@ public class MainActivity extends ReplayableActivity
|
|||||||
ReminderHelper.createReminderAlarms(MainActivity.this);
|
ReminderHelper.createReminderAlarms(MainActivity.this);
|
||||||
DialogHelper.incrementLaunchCount(this);
|
DialogHelper.incrementLaunchCount(this);
|
||||||
showTutorial();
|
showTutorial();
|
||||||
|
updateWidgets(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showTutorial()
|
private void showTutorial()
|
||||||
@@ -108,5 +128,40 @@ public class MainActivity extends ReplayableActivity
|
|||||||
public void onPostExecuteCommand(Long refreshKey)
|
public void onPostExecuteCommand(Long refreshKey)
|
||||||
{
|
{
|
||||||
listHabitsFragment.onPostExecuteCommand(refreshKey);
|
listHabitsFragment.onPostExecuteCommand(refreshKey);
|
||||||
|
updateWidgets(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateWidgets(Context context)
|
||||||
|
{
|
||||||
|
updateWidgets(context, CheckmarkWidgetProvider.class);
|
||||||
|
updateWidgets(context, HistoryWidgetProvider.class);
|
||||||
|
updateWidgets(context, ScoreWidgetProvider.class);
|
||||||
|
updateWidgets(context, StreakWidgetProvider.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateWidgets(Context context, Class providerClass)
|
||||||
|
{
|
||||||
|
ComponentName provider = new ComponentName(context, providerClass);
|
||||||
|
Intent intent = new Intent(context, providerClass);
|
||||||
|
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
||||||
|
int ids[] = AppWidgetManager.getInstance(context).getAppWidgetIds(provider);
|
||||||
|
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
|
||||||
|
context.sendBroadcast(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy()
|
||||||
|
{
|
||||||
|
localBroadcastManager.unregisterReceiver(receiver);
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Receiver extends BroadcastReceiver
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
listHabitsFragment.onPostExecuteCommand(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -660,7 +660,7 @@ public class ListHabitsFragment extends Fragment
|
|||||||
|
|
||||||
LinearLayout.LayoutParams params =
|
LinearLayout.LayoutParams params =
|
||||||
new LinearLayout.LayoutParams(tvNameWidth, LayoutParams.WRAP_CONTENT, 1);
|
new LinearLayout.LayoutParams(tvNameWidth, LayoutParams.WRAP_CONTENT, 1);
|
||||||
view.findViewById(R.id.tvName).setLayoutParams(params);
|
view.findViewById(R.id.label).setLayoutParams(params);
|
||||||
|
|
||||||
inflateCheckmarkButtons(view);
|
inflateCheckmarkButtons(view);
|
||||||
|
|
||||||
@@ -668,7 +668,7 @@ public class ListHabitsFragment extends Fragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
TextView tvStar = ((TextView) view.findViewById(R.id.tvStar));
|
TextView tvStar = ((TextView) view.findViewById(R.id.tvStar));
|
||||||
TextView tvName = (TextView) view.findViewById(R.id.tvName);
|
TextView tvName = (TextView) view.findViewById(R.id.label);
|
||||||
LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner);
|
LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner);
|
||||||
LinearLayout llButtons = (LinearLayout) view.findViewById(R.id.llButtons);
|
LinearLayout llButtons = (LinearLayout) view.findViewById(R.id.llButtons);
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import android.os.Build;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.isoron.helpers.DateHelper;
|
import org.isoron.helpers.DateHelper;
|
||||||
import org.isoron.uhabits.ReminderAlarmReceiver;
|
import org.isoron.uhabits.HabitBroadcastReceiver;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
@@ -58,10 +58,10 @@ public class ReminderHelper
|
|||||||
|
|
||||||
long timestamp = DateHelper.getStartOfDay(DateHelper.toLocalTime(reminderTime));
|
long timestamp = DateHelper.getStartOfDay(DateHelper.toLocalTime(reminderTime));
|
||||||
|
|
||||||
Uri uri = Uri.parse(String.format("content://org.isoron.uhabits/habit/%d", habit.getId()));
|
Uri uri = habit.getUri();
|
||||||
|
|
||||||
Intent alarmIntent = new Intent(context, ReminderAlarmReceiver.class);
|
Intent alarmIntent = new Intent(context, HabitBroadcastReceiver.class);
|
||||||
alarmIntent.setAction(ReminderAlarmReceiver.ACTION_REMIND);
|
alarmIntent.setAction(HabitBroadcastReceiver.ACTION_SHOW_REMINDER);
|
||||||
alarmIntent.setData(uri);
|
alarmIntent.setData(uri);
|
||||||
alarmIntent.putExtra("timestamp", timestamp);
|
alarmIntent.putExtra("timestamp", timestamp);
|
||||||
alarmIntent.putExtra("reminderTime", reminderTime);
|
alarmIntent.putExtra("reminderTime", reminderTime);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.isoron.uhabits.models;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
import com.activeandroid.ActiveAndroid;
|
import com.activeandroid.ActiveAndroid;
|
||||||
import com.activeandroid.Cache;
|
import com.activeandroid.Cache;
|
||||||
@@ -383,6 +384,24 @@ public class Habit extends Model
|
|||||||
.executeSingle();
|
.executeSingle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCurrentCheckmarkStatus()
|
||||||
|
{
|
||||||
|
updateCheckmarks();
|
||||||
|
Checkmark c = getNewestCheckmark();
|
||||||
|
|
||||||
|
if(c != null) return c.value;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCurrentStarStatus()
|
||||||
|
{
|
||||||
|
int score = getScore();
|
||||||
|
|
||||||
|
if(score >= FULL_STAR_CUTOFF) return 2;
|
||||||
|
else if(score >= HALF_STAR_CUTOFF) return 1;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public int getRepsCount(int days)
|
public int getRepsCount(int days)
|
||||||
{
|
{
|
||||||
long timeTo = DateHelper.getStartOfToday();
|
long timeTo = DateHelper.getStartOfToday();
|
||||||
@@ -426,6 +445,11 @@ public class Habit extends Model
|
|||||||
deleteStreaksNewerThan(timestamp);
|
deleteStreaksNewerThan(timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Uri getUri()
|
||||||
|
{
|
||||||
|
return Uri.parse(String.format("content://org.isoron.uhabits/habit/%d", getId()));
|
||||||
|
}
|
||||||
|
|
||||||
public void archive()
|
public void archive()
|
||||||
{
|
{
|
||||||
archived = 1;
|
archived = 1;
|
||||||
|
|||||||
212
app/src/main/java/org/isoron/uhabits/views/CheckmarkView.java
Normal file
212
app/src/main/java/org/isoron/uhabits/views/CheckmarkView.java
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
/* Copyright (C) 2016 Alinson Santos Xavier
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* This program 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.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.text.Layout;
|
||||||
|
import android.text.StaticLayout;
|
||||||
|
import android.text.TextPaint;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.isoron.helpers.ColorHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
|
public class CheckmarkView extends View
|
||||||
|
{
|
||||||
|
private Paint pCard;
|
||||||
|
private Paint pIcon;
|
||||||
|
|
||||||
|
private int primaryColor;
|
||||||
|
private int backgroundColor;
|
||||||
|
private int timesColor;
|
||||||
|
private int darkGrey;
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
private int leftMargin;
|
||||||
|
private int topMargin;
|
||||||
|
private int padding;
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
private String fa_check;
|
||||||
|
private String fa_times;
|
||||||
|
private String fa_full_star;
|
||||||
|
private String fa_half_star;
|
||||||
|
private String fa_empty_star;
|
||||||
|
|
||||||
|
private int check_status;
|
||||||
|
private int star_status;
|
||||||
|
|
||||||
|
private Rect rect;
|
||||||
|
private TextPaint textPaint;
|
||||||
|
private StaticLayout labelLayout;
|
||||||
|
|
||||||
|
public CheckmarkView(Context context)
|
||||||
|
{
|
||||||
|
super(context);
|
||||||
|
init(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckmarkView(Context context, AttributeSet attrs)
|
||||||
|
{
|
||||||
|
super(context, attrs);
|
||||||
|
init(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(Context context)
|
||||||
|
{
|
||||||
|
Typeface fontawesome =
|
||||||
|
Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
|
||||||
|
|
||||||
|
pCard = new Paint();
|
||||||
|
pCard.setAntiAlias(true);
|
||||||
|
|
||||||
|
pIcon = new Paint();
|
||||||
|
pIcon.setAntiAlias(true);
|
||||||
|
pIcon.setTypeface(fontawesome);
|
||||||
|
pIcon.setTextAlign(Paint.Align.CENTER);
|
||||||
|
|
||||||
|
textPaint = new TextPaint();
|
||||||
|
textPaint.setColor(Color.WHITE);
|
||||||
|
textPaint.setAntiAlias(true);
|
||||||
|
|
||||||
|
fa_check = context.getString(R.string.fa_check);
|
||||||
|
fa_times = context.getString(R.string.fa_times);
|
||||||
|
fa_empty_star = context.getString(R.string.fa_star_o);
|
||||||
|
fa_half_star = context.getString(R.string.fa_star_half_o);
|
||||||
|
fa_full_star = context.getString(R.string.fa_star);
|
||||||
|
|
||||||
|
primaryColor = ColorHelper.palette[10];
|
||||||
|
backgroundColor = Color.argb(255, 255, 255, 255);
|
||||||
|
timesColor = Color.argb(128, 255, 255, 255);
|
||||||
|
darkGrey = Color.argb(64, 0, 0, 0);
|
||||||
|
|
||||||
|
rect = new Rect();
|
||||||
|
check_status = 2;
|
||||||
|
star_status = 0;
|
||||||
|
label = "Wake up early";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHabit(Habit habit)
|
||||||
|
{
|
||||||
|
this.check_status = habit.getCurrentCheckmarkStatus();
|
||||||
|
this.star_status = habit.getCurrentStarStatus();
|
||||||
|
this.primaryColor = Color.argb(230, Color.red(habit.color), Color.green(habit.color), Color.blue(habit.color));
|
||||||
|
this.label = habit.name;
|
||||||
|
updateLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas)
|
||||||
|
{
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
drawBackground(canvas);
|
||||||
|
drawCheckmark(canvas);
|
||||||
|
drawLabel(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawBackground(Canvas canvas)
|
||||||
|
{
|
||||||
|
int color = (check_status == 2 ? primaryColor : darkGrey);
|
||||||
|
|
||||||
|
pCard.setColor(color);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
{
|
||||||
|
canvas.drawRoundRect(leftMargin, topMargin, width - leftMargin, height - topMargin, padding,
|
||||||
|
padding, pCard);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
canvas.drawRect(leftMargin, topMargin, width - leftMargin, height - topMargin, pCard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawCheckmark(Canvas canvas)
|
||||||
|
{
|
||||||
|
String text = (check_status == 0 ? fa_times : fa_check);
|
||||||
|
int color = (check_status == 2 ? Color.WHITE : timesColor);
|
||||||
|
|
||||||
|
pIcon.setColor(color);
|
||||||
|
pIcon.setTextSize(width * 0.5f);
|
||||||
|
pIcon.getTextBounds(text, 0, 1, rect);
|
||||||
|
|
||||||
|
// canvas.drawLine(0, 0.67f * height, width, 0.67f * height, pIcon);
|
||||||
|
|
||||||
|
int y = (int) ((0.67f * height - rect.bottom - rect.top) / 2);
|
||||||
|
canvas.drawText(text, width / 2, y, pIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawLabel(Canvas canvas)
|
||||||
|
{
|
||||||
|
canvas.save();
|
||||||
|
float y;
|
||||||
|
int nLines = labelLayout.getLineCount();
|
||||||
|
|
||||||
|
if(nLines == 1)
|
||||||
|
y = height * 0.8f - padding;
|
||||||
|
else
|
||||||
|
y = height * 0.7f - padding;
|
||||||
|
|
||||||
|
canvas.translate(leftMargin + padding, y);
|
||||||
|
|
||||||
|
labelLayout.draw(canvas);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int width, int height)
|
||||||
|
{
|
||||||
|
super.onMeasure(width, height);
|
||||||
|
setMeasuredDimension(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
||||||
|
{
|
||||||
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
updateSize(w, h);
|
||||||
|
updateLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSize(int width, int height)
|
||||||
|
{
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
|
||||||
|
leftMargin = (int) (width * 0.015);
|
||||||
|
topMargin = (int) (height * 0.015);
|
||||||
|
padding = 8 * leftMargin;
|
||||||
|
textPaint.setTextSize(0.15f * width);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLabel()
|
||||||
|
{
|
||||||
|
textPaint.setColor(Color.WHITE);
|
||||||
|
labelLayout = new StaticLayout(label, textPaint, width - 2 * leftMargin - 2 * padding,
|
||||||
|
Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -26,7 +26,6 @@ import android.util.AttributeSet;
|
|||||||
|
|
||||||
import org.isoron.helpers.ColorHelper;
|
import org.isoron.helpers.ColorHelper;
|
||||||
import org.isoron.helpers.DateHelper;
|
import org.isoron.helpers.DateHelper;
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@@ -45,6 +44,11 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
private float squareTextOffset;
|
private float squareTextOffset;
|
||||||
private float headerTextOffset;
|
private float headerTextOffset;
|
||||||
|
|
||||||
|
private int columnWidth;
|
||||||
|
private int columnHeight;
|
||||||
|
private int nColumns;
|
||||||
|
private int baseSize;
|
||||||
|
|
||||||
private String wdays[];
|
private String wdays[];
|
||||||
private SimpleDateFormat dfMonth;
|
private SimpleDateFormat dfMonth;
|
||||||
private SimpleDateFormat dfYear;
|
private SimpleDateFormat dfYear;
|
||||||
@@ -54,14 +58,12 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
private int todayWeekday;
|
private int todayWeekday;
|
||||||
private int colors[];
|
private int colors[];
|
||||||
private Rect baseLocation;
|
private Rect baseLocation;
|
||||||
private int baseSize;
|
|
||||||
private int primaryColor;
|
private int primaryColor;
|
||||||
|
|
||||||
public HabitHistoryView(Context context, AttributeSet attrs)
|
public HabitHistoryView(Context context, AttributeSet attrs)
|
||||||
{
|
{
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
this.primaryColor = ColorHelper.palette[7];
|
this.primaryColor = ColorHelper.palette[7];
|
||||||
this.baseSize = (int) context.getResources().getDimension(R.dimen.small_square_size);
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +78,6 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
|
|
||||||
private void init()
|
private void init()
|
||||||
{
|
{
|
||||||
setDimensions(this.baseSize);
|
|
||||||
createPaints();
|
createPaints();
|
||||||
createColors();
|
createColors();
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
private void updateDate()
|
private void updateDate()
|
||||||
{
|
{
|
||||||
baseDate = new GregorianCalendar();
|
baseDate = new GregorianCalendar();
|
||||||
baseDate.add(Calendar.DAY_OF_YEAR, -(dataOffset - 1) * 7);
|
baseDate.add(Calendar.DAY_OF_YEAR, -(getDataOffset() - 1) * 7);
|
||||||
|
|
||||||
nDays = (nColumns - 1) * 7;
|
nDays = (nColumns - 1) * 7;
|
||||||
todayWeekday = new GregorianCalendar().get(Calendar.DAY_OF_WEEK) % 7;
|
todayWeekday = new GregorianCalendar().get(Calendar.DAY_OF_WEEK) % 7;
|
||||||
@@ -100,16 +101,42 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||||
{
|
{
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
int height = MeasureSpec.getSize(heightMeasureSpec);
|
||||||
|
|
||||||
|
int b = height / 8;
|
||||||
|
height = b * 8;
|
||||||
|
width = (width / b) * b;
|
||||||
|
|
||||||
|
setMeasuredDimension(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight)
|
||||||
|
{
|
||||||
|
baseSize = height / 8;
|
||||||
|
setScrollerBucketSize(baseSize);
|
||||||
|
|
||||||
|
columnWidth = baseSize;
|
||||||
|
columnHeight = 8 * baseSize;
|
||||||
|
nColumns = width / baseSize;
|
||||||
|
|
||||||
|
squareSpacing = baseSize / 10;
|
||||||
|
pSquareFg.setTextSize(baseSize * 0.5f);
|
||||||
|
pTextHeader.setTextSize(baseSize * 0.5f);
|
||||||
|
squareTextOffset = pSquareFg.getFontSpacing() * 0.4f;
|
||||||
|
headerTextOffset = pTextHeader.getFontSpacing() * 0.3f;
|
||||||
|
|
||||||
updateDate();
|
updateDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createColors()
|
private void createColors()
|
||||||
{
|
{
|
||||||
int primaryColorBright = ColorHelper.mixColors(primaryColor, Color.WHITE, 0.5f);
|
int primaryColorBright = Color.argb(127, Color.red(primaryColor), Color.green(primaryColor),
|
||||||
int grey = Color.rgb(230, 230, 230);
|
Color.blue(primaryColor));
|
||||||
|
int grey = Color.argb(25, 0, 0, 0);
|
||||||
|
|
||||||
colors = new int[3];
|
colors = new int[3];
|
||||||
colors[0] = grey;
|
colors[0] = grey;
|
||||||
@@ -117,19 +144,11 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
colors[2] = primaryColor;
|
colors[2] = primaryColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDimensions(int baseSize)
|
protected void createPaints()
|
||||||
{
|
|
||||||
columnWidth = baseSize;
|
|
||||||
columnHeight = 8 * baseSize;
|
|
||||||
squareSpacing = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createPaints()
|
|
||||||
{
|
{
|
||||||
pTextHeader = new Paint();
|
pTextHeader = new Paint();
|
||||||
pTextHeader.setColor(Color.LTGRAY);
|
pTextHeader.setColor(Color.argb(64, 0, 0, 0));
|
||||||
pTextHeader.setTextAlign(Align.LEFT);
|
pTextHeader.setTextAlign(Align.LEFT);
|
||||||
pTextHeader.setTextSize(columnWidth * 0.5f);
|
|
||||||
pTextHeader.setAntiAlias(true);
|
pTextHeader.setAntiAlias(true);
|
||||||
|
|
||||||
pSquareBg = new Paint();
|
pSquareBg = new Paint();
|
||||||
@@ -138,11 +157,7 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
pSquareFg = new Paint();
|
pSquareFg = new Paint();
|
||||||
pSquareFg.setColor(Color.WHITE);
|
pSquareFg.setColor(Color.WHITE);
|
||||||
pSquareFg.setAntiAlias(true);
|
pSquareFg.setAntiAlias(true);
|
||||||
pSquareFg.setTextSize(columnWidth * 0.5f);
|
|
||||||
pSquareFg.setTextAlign(Align.CENTER);
|
pSquareFg.setTextAlign(Align.CENTER);
|
||||||
|
|
||||||
squareTextOffset = pSquareFg.getFontSpacing() * 0.4f;
|
|
||||||
headerTextOffset = pTextHeader.getFontSpacing() * 0.3f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void fetchData()
|
protected void fetchData()
|
||||||
@@ -203,7 +218,7 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
for (int column = 0; column < nColumns - 1; column++)
|
for (int column = 0; column < nColumns - 1; column++)
|
||||||
{
|
{
|
||||||
drawColumn(canvas, baseLocation, currentDate, column);
|
drawColumn(canvas, baseLocation, currentDate, column);
|
||||||
baseLocation.offset(columnWidth, -columnHeight);
|
baseLocation.offset(columnWidth, - columnHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawAxis(canvas, baseLocation);
|
drawAxis(canvas, baseLocation);
|
||||||
@@ -216,9 +231,9 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
|
|
||||||
for (int j = 0; j < 7; j++)
|
for (int j = 0; j < 7; j++)
|
||||||
{
|
{
|
||||||
if (!(column == nColumns - 2 && dataOffset == 0 && j > todayWeekday))
|
if (!(column == nColumns - 2 && getDataOffset() == 0 && j > todayWeekday))
|
||||||
{
|
{
|
||||||
int checkmarkOffset = dataOffset * 7 + nDays - 7 * (column + 1) + todayWeekday - j;
|
int checkmarkOffset = getDataOffset() * 7 + nDays - 7 * (column + 1) + todayWeekday - j;
|
||||||
drawSquare(canvas, location, date, checkmarkOffset);
|
drawSquare(canvas, location, date, checkmarkOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +263,8 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean justSkippedColumn = false;
|
||||||
|
|
||||||
private void drawColumnHeader(Canvas canvas, Rect location, GregorianCalendar date)
|
private void drawColumnHeader(Canvas canvas, Rect location, GregorianCalendar date)
|
||||||
{
|
{
|
||||||
String month = dfMonth.format(date.getTime());
|
String month = dfMonth.format(date.getTime());
|
||||||
@@ -256,21 +273,32 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
if (!month.equals(previousMonth))
|
if (!month.equals(previousMonth))
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
if (justPrintedYear) offset += columnWidth;
|
if (justPrintedYear)
|
||||||
|
{
|
||||||
|
offset += columnWidth;
|
||||||
|
justSkippedColumn = true;
|
||||||
|
}
|
||||||
|
|
||||||
canvas.drawText(month, location.left + offset, location.bottom - headerTextOffset,
|
canvas.drawText(month, location.left + offset, location.bottom - headerTextOffset,
|
||||||
pTextHeader);
|
pTextHeader);
|
||||||
|
|
||||||
previousMonth = month;
|
previousMonth = month;
|
||||||
justPrintedYear = false;
|
justPrintedYear = false;
|
||||||
}
|
}
|
||||||
else if (!year.equals(previousYear))
|
else if (!year.equals(previousYear))
|
||||||
{
|
{
|
||||||
canvas.drawText(year, location.left, location.bottom - headerTextOffset, pTextHeader);
|
if(!justSkippedColumn)
|
||||||
previousYear = year;
|
{
|
||||||
justPrintedYear = true;
|
canvas.drawText(year, location.left, location.bottom - headerTextOffset, pTextHeader);
|
||||||
|
previousYear = year;
|
||||||
|
justPrintedYear = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
justSkippedColumn = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
justSkippedColumn = false;
|
||||||
justPrintedYear = false;
|
justPrintedYear = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,13 @@ import android.content.Context;
|
|||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.PorterDuffXfermode;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
import org.isoron.helpers.ColorHelper;
|
import org.isoron.helpers.ColorHelper;
|
||||||
import org.isoron.helpers.DateHelper;
|
import org.isoron.helpers.DateHelper;
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@@ -35,6 +36,10 @@ import java.util.Random;
|
|||||||
public class HabitScoreView extends ScrollableDataView
|
public class HabitScoreView extends ScrollableDataView
|
||||||
{
|
{
|
||||||
public static final int BUCKET_SIZE = 7;
|
public static final int BUCKET_SIZE = 7;
|
||||||
|
public static final PorterDuffXfermode XFERMODE_CLEAR =
|
||||||
|
new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
|
||||||
|
public static final PorterDuffXfermode XFERMODE_SRC =
|
||||||
|
new PorterDuffXfermode(PorterDuff.Mode.SRC);
|
||||||
|
|
||||||
private Paint pGrid;
|
private Paint pGrid;
|
||||||
private float em;
|
private float em;
|
||||||
@@ -46,14 +51,18 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
private RectF rect, prevRect;
|
private RectF rect, prevRect;
|
||||||
private int baseSize;
|
private int baseSize;
|
||||||
|
|
||||||
|
private int columnWidth;
|
||||||
|
private int columnHeight;
|
||||||
|
private int nColumns;
|
||||||
|
|
||||||
private int[] colors;
|
private int[] colors;
|
||||||
private int[] scores;
|
private int[] scores;
|
||||||
private int primaryColor;
|
private int primaryColor;
|
||||||
|
private boolean isBackgroundTransparent;
|
||||||
|
|
||||||
public HabitScoreView(Context context, AttributeSet attrs)
|
public HabitScoreView(Context context, AttributeSet attrs)
|
||||||
{
|
{
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
this.baseSize = (int) context.getResources().getDimension(R.dimen.small_square_size);
|
|
||||||
this.primaryColor = ColorHelper.palette[7];
|
this.primaryColor = ColorHelper.palette[7];
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
@@ -69,7 +78,6 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
private void init()
|
private void init()
|
||||||
{
|
{
|
||||||
createPaints();
|
createPaints();
|
||||||
setDimensions();
|
|
||||||
createColors();
|
createColors();
|
||||||
|
|
||||||
dfMonth = new SimpleDateFormat("MMM", Locale.getDefault());
|
dfMonth = new SimpleDateFormat("MMM", Locale.getDefault());
|
||||||
@@ -79,15 +87,6 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
prevRect = new RectF();
|
prevRect = new RectF();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDimensions()
|
|
||||||
{
|
|
||||||
this.columnWidth = baseSize;
|
|
||||||
columnHeight = 8 * baseSize;
|
|
||||||
headerHeight = baseSize;
|
|
||||||
footerHeight = baseSize;
|
|
||||||
em = pText.getFontSpacing();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createColors()
|
private void createColors()
|
||||||
{
|
{
|
||||||
colors = new int[4];
|
colors = new int[4];
|
||||||
@@ -98,24 +97,54 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
colors[2] = ColorHelper.mixColors(colors[0], colors[3], 0.33f);
|
colors[2] = ColorHelper.mixColors(colors[0], colors[3], 0.33f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPaints()
|
protected void createPaints()
|
||||||
{
|
{
|
||||||
pText = new Paint();
|
pText = new Paint();
|
||||||
pText.setColor(Color.LTGRAY);
|
pText.setColor(Color.argb(64, 0, 0, 0));
|
||||||
pText.setTextAlign(Paint.Align.LEFT);
|
pText.setTextAlign(Paint.Align.LEFT);
|
||||||
pText.setTextSize(baseSize * 0.5f);
|
|
||||||
pText.setAntiAlias(true);
|
pText.setAntiAlias(true);
|
||||||
|
|
||||||
pGraph = new Paint();
|
pGraph = new Paint();
|
||||||
pGraph.setTextAlign(Paint.Align.CENTER);
|
pGraph.setTextAlign(Paint.Align.CENTER);
|
||||||
pGraph.setTextSize(baseSize * 0.5f);
|
|
||||||
pGraph.setAntiAlias(true);
|
pGraph.setAntiAlias(true);
|
||||||
pGraph.setStrokeWidth(baseSize * 0.1f);
|
|
||||||
|
|
||||||
pGrid = new Paint();
|
pGrid = new Paint();
|
||||||
pGrid.setColor(Color.LTGRAY);
|
pGrid.setColor(Color.argb(64, 0, 0, 0));
|
||||||
pGrid.setAntiAlias(true);
|
pGrid.setAntiAlias(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||||
|
{
|
||||||
|
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
int height = MeasureSpec.getSize(heightMeasureSpec);
|
||||||
|
|
||||||
|
if(height > 0)
|
||||||
|
{
|
||||||
|
int b = height / 9;
|
||||||
|
height = b * 9;
|
||||||
|
width = (width / b) * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
setMeasuredDimension(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight)
|
||||||
|
{
|
||||||
|
baseSize = height / 9;
|
||||||
|
setScrollerBucketSize(baseSize);
|
||||||
|
|
||||||
|
columnWidth = baseSize;
|
||||||
|
columnHeight = 8 * baseSize;
|
||||||
|
nColumns = width / baseSize;
|
||||||
|
|
||||||
|
pText.setTextSize(baseSize * 0.5f);
|
||||||
|
pGraph.setTextSize(baseSize * 0.5f);
|
||||||
|
pGraph.setStrokeWidth(baseSize * 0.1f);
|
||||||
pGrid.setStrokeWidth(baseSize * 0.05f);
|
pGrid.setStrokeWidth(baseSize * 0.05f);
|
||||||
|
em = pText.getFontSpacing();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void fetchData()
|
protected void fetchData()
|
||||||
@@ -157,7 +186,6 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
float lineHeight = pText.getFontSpacing();
|
float lineHeight = pText.getFontSpacing();
|
||||||
|
|
||||||
rect.set(0, 0, nColumns * columnWidth, columnHeight);
|
rect.set(0, 0, nColumns * columnWidth, columnHeight);
|
||||||
rect.offset(0, headerHeight);
|
|
||||||
drawGrid(canvas, rect);
|
drawGrid(canvas, rect);
|
||||||
|
|
||||||
String previousMonth = "";
|
String previousMonth = "";
|
||||||
@@ -167,7 +195,7 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
|
|
||||||
long currentDate = DateHelper.getStartOfToday();
|
long currentDate = DateHelper.getStartOfToday();
|
||||||
|
|
||||||
for(int k = 0; k < nColumns + dataOffset - 1; k++)
|
for(int k = 0; k < nColumns + getDataOffset() - 1; k++)
|
||||||
currentDate -= 7 * DateHelper.millisecondsInOneDay;
|
currentDate -= 7 * DateHelper.millisecondsInOneDay;
|
||||||
|
|
||||||
for (int k = 0; k < nColumns; k++)
|
for (int k = 0; k < nColumns; k++)
|
||||||
@@ -176,15 +204,14 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
String day = dfDay.format(currentDate);
|
String day = dfDay.format(currentDate);
|
||||||
|
|
||||||
int score = 0;
|
int score = 0;
|
||||||
int offset = nColumns - k - 1 + dataOffset;
|
int offset = nColumns - k - 1 + getDataOffset();
|
||||||
if(offset < scores.length) score = scores[offset];
|
if(offset < scores.length) score = scores[offset];
|
||||||
|
|
||||||
double sRelative = ((double) score) / Habit.MAX_SCORE;
|
double sRelative = ((double) score) / Habit.MAX_SCORE;
|
||||||
int height = (int) (columnHeight * sRelative);
|
int height = (int) (columnHeight * sRelative);
|
||||||
|
|
||||||
rect.set(0, 0, columnWidth, columnWidth);
|
rect.set(0, 0, baseSize, baseSize);
|
||||||
rect.offset(k * columnWidth,
|
rect.offset(k * columnWidth, columnHeight - height - columnWidth / 2);
|
||||||
headerHeight + columnHeight - height - columnWidth / 2);
|
|
||||||
|
|
||||||
if (!prevRect.isEmpty())
|
if (!prevRect.isEmpty())
|
||||||
{
|
{
|
||||||
@@ -197,7 +224,7 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
prevRect.set(rect);
|
prevRect.set(rect);
|
||||||
|
|
||||||
rect.set(0, 0, columnWidth, columnHeight);
|
rect.set(0, 0, columnWidth, columnHeight);
|
||||||
rect.offset(k * columnWidth, headerHeight);
|
rect.offset(k * columnWidth, 0);
|
||||||
if (!month.equals(previousMonth))
|
if (!month.equals(previousMonth))
|
||||||
canvas.drawText(month, rect.centerX(), rect.bottom + lineHeight * 1.2f, pText);
|
canvas.drawText(month, rect.centerX(), rect.bottom + lineHeight * 1.2f, pText);
|
||||||
else
|
else
|
||||||
@@ -213,7 +240,7 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
int nRows = 5;
|
int nRows = 5;
|
||||||
float rowHeight = rGrid.height() / nRows;
|
float rowHeight = rGrid.height() / nRows;
|
||||||
|
|
||||||
pGrid.setColor(Color.rgb(240, 240, 240));
|
pGrid.setColor(Color.argb(20, 0, 0, 0));
|
||||||
for (int i = 0; i < nRows; i++)
|
for (int i = 0; i < nRows; i++)
|
||||||
{
|
{
|
||||||
canvas.drawText(String.format("%d%%", (100 - i * 100 / nRows)), rGrid.left + 0.5f * em,
|
canvas.drawText(String.format("%d%%", (100 - i * 100 / nRows)), rGrid.left + 0.5f * em,
|
||||||
@@ -235,15 +262,31 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
private void drawMarker(Canvas canvas, RectF rect)
|
private void drawMarker(Canvas canvas, RectF rect)
|
||||||
{
|
{
|
||||||
rect.inset(columnWidth * 0.15f, columnWidth * 0.15f);
|
rect.inset(columnWidth * 0.15f, columnWidth * 0.15f);
|
||||||
pGraph.setColor(Color.WHITE);
|
setModeOrColor(pGraph, XFERMODE_CLEAR, Color.WHITE);
|
||||||
canvas.drawOval(rect, pGraph);
|
canvas.drawOval(rect, pGraph);
|
||||||
|
|
||||||
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
|
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
|
||||||
pGraph.setColor(primaryColor);
|
setModeOrColor(pGraph, XFERMODE_SRC, primaryColor);
|
||||||
canvas.drawOval(rect, pGraph);
|
canvas.drawOval(rect, pGraph);
|
||||||
|
|
||||||
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
|
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
|
||||||
pGraph.setColor(Color.WHITE);
|
setModeOrColor(pGraph, XFERMODE_CLEAR, Color.WHITE);
|
||||||
canvas.drawOval(rect, pGraph);
|
canvas.drawOval(rect, pGraph);
|
||||||
|
|
||||||
|
if(isBackgroundTransparent)
|
||||||
|
pGraph.setXfermode(XFERMODE_SRC);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
|
||||||
|
{
|
||||||
|
this.isBackgroundTransparent = isBackgroundTransparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setModeOrColor(Paint p, PorterDuffXfermode mode, int color)
|
||||||
|
{
|
||||||
|
if(isBackgroundTransparent)
|
||||||
|
p.setXfermode(mode);
|
||||||
|
else
|
||||||
|
p.setColor(color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ public class HabitStreakView extends ScrollableDataView
|
|||||||
private long[] endTimes;
|
private long[] endTimes;
|
||||||
private long[] lengths;
|
private long[] lengths;
|
||||||
|
|
||||||
|
private int columnWidth;
|
||||||
|
private int columnHeight;
|
||||||
|
private int headerHeight;
|
||||||
|
private int nColumns;
|
||||||
|
|
||||||
private long maxStreakLength;
|
private long maxStreakLength;
|
||||||
private int[] colors;
|
private int[] colors;
|
||||||
private SimpleDateFormat dfMonth;
|
private SimpleDateFormat dfMonth;
|
||||||
@@ -53,7 +58,6 @@ public class HabitStreakView extends ScrollableDataView
|
|||||||
public HabitStreakView(Context context, AttributeSet attrs)
|
public HabitStreakView(Context context, AttributeSet attrs)
|
||||||
{
|
{
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
this.baseSize = (int) context.getResources().getDimension(R.dimen.small_square_size);
|
|
||||||
this.primaryColor = ColorHelper.palette[7];
|
this.primaryColor = ColorHelper.palette[7];
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
@@ -62,6 +66,7 @@ public class HabitStreakView extends ScrollableDataView
|
|||||||
{
|
{
|
||||||
this.habit = habit;
|
this.habit = habit;
|
||||||
this.primaryColor = habit.color;
|
this.primaryColor = habit.color;
|
||||||
|
|
||||||
createColors();
|
createColors();
|
||||||
fetchData();
|
fetchData();
|
||||||
postInvalidate();
|
postInvalidate();
|
||||||
@@ -69,7 +74,6 @@ public class HabitStreakView extends ScrollableDataView
|
|||||||
|
|
||||||
private void init()
|
private void init()
|
||||||
{
|
{
|
||||||
setDimensions(baseSize);
|
|
||||||
createPaints();
|
createPaints();
|
||||||
createColors();
|
createColors();
|
||||||
|
|
||||||
@@ -77,34 +81,54 @@ public class HabitStreakView extends ScrollableDataView
|
|||||||
rect = new Rect();
|
rect = new Rect();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDimensions(int baseSize)
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||||
{
|
{
|
||||||
this.columnWidth = baseSize;
|
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
int height = MeasureSpec.getSize(heightMeasureSpec);
|
||||||
|
|
||||||
|
int b = height / 10;
|
||||||
|
height = b * 10;
|
||||||
|
width = (width / b) * b;
|
||||||
|
|
||||||
|
setMeasuredDimension(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight)
|
||||||
|
{
|
||||||
|
baseSize = height / 10;
|
||||||
|
setScrollerBucketSize(baseSize);
|
||||||
|
|
||||||
|
columnWidth = baseSize;
|
||||||
columnHeight = 8 * baseSize;
|
columnHeight = 8 * baseSize;
|
||||||
headerHeight = baseSize;
|
headerHeight = baseSize;
|
||||||
footerHeight = baseSize;
|
nColumns = width / baseSize - 1;
|
||||||
|
|
||||||
|
pText.setTextSize(baseSize * 0.5f);
|
||||||
|
pBar.setTextSize(baseSize * 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createColors()
|
private void createColors()
|
||||||
{
|
{
|
||||||
colors = new int[4];
|
colors = new int[4];
|
||||||
colors[0] = Color.rgb(230, 230, 230);
|
|
||||||
colors[3] = primaryColor;
|
colors[3] = primaryColor;
|
||||||
colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f);
|
colors[1] = Color.argb(80, Color.red(primaryColor), Color.green(primaryColor), Color.blue(
|
||||||
colors[2] = ColorHelper.mixColors(colors[0], colors[3], 0.33f);
|
primaryColor));
|
||||||
|
colors[2] = Color.argb(170, Color.red(primaryColor), Color.green(primaryColor),
|
||||||
|
Color.blue(primaryColor));
|
||||||
|
colors[0] = Color.argb(30, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPaints()
|
protected void createPaints()
|
||||||
{
|
{
|
||||||
pText = new Paint();
|
pText = new Paint();
|
||||||
pText.setColor(Color.LTGRAY);
|
pText.setColor(Color.argb(64, 0, 0, 0));
|
||||||
pText.setTextAlign(Paint.Align.CENTER);
|
pText.setTextAlign(Paint.Align.CENTER);
|
||||||
pText.setTextSize(columnWidth * 0.5f);
|
|
||||||
pText.setAntiAlias(true);
|
pText.setAntiAlias(true);
|
||||||
|
|
||||||
pBar = new Paint();
|
pBar = new Paint();
|
||||||
pBar.setTextAlign(Paint.Align.CENTER);
|
pBar.setTextAlign(Paint.Align.CENTER);
|
||||||
pBar.setTextSize(columnWidth * 0.5f);
|
|
||||||
pBar.setAntiAlias(true);
|
pBar.setAntiAlias(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +197,7 @@ public class HabitStreakView extends ScrollableDataView
|
|||||||
float barHeaderOffset = lineHeight * 0.4f;
|
float barHeaderOffset = lineHeight * 0.4f;
|
||||||
|
|
||||||
int nStreaks = startTimes.length;
|
int nStreaks = startTimes.length;
|
||||||
int start = nStreaks - nColumns - dataOffset;
|
int start = nStreaks - nColumns - getDataOffset();
|
||||||
|
|
||||||
String previousMonth = "";
|
String previousMonth = "";
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,8 @@ public abstract class ScrollableDataView extends View implements GestureDetector
|
|||||||
ValueAnimator.AnimatorUpdateListener
|
ValueAnimator.AnimatorUpdateListener
|
||||||
{
|
{
|
||||||
|
|
||||||
protected int dataOffset;
|
private int dataOffset;
|
||||||
protected int nColumns;
|
private int scrollerBucketSize;
|
||||||
protected int columnWidth, columnHeight;
|
|
||||||
protected int headerHeight, footerHeight;
|
|
||||||
|
|
||||||
private GestureDetector detector;
|
private GestureDetector detector;
|
||||||
private Scroller scroller;
|
private Scroller scroller;
|
||||||
@@ -68,21 +66,6 @@ public abstract class ScrollableDataView extends View implements GestureDetector
|
|||||||
return detector.onTouchEvent(event);
|
return detector.onTouchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
|
||||||
{
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
||||||
setMeasuredDimension(getMeasuredWidth(), columnHeight + headerHeight + footerHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
|
||||||
{
|
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
|
||||||
nColumns = w / columnWidth;
|
|
||||||
fetchData();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onDown(MotionEvent e)
|
public boolean onDown(MotionEvent e)
|
||||||
{
|
{
|
||||||
@@ -104,13 +87,17 @@ public abstract class ScrollableDataView extends View implements GestureDetector
|
|||||||
@Override
|
@Override
|
||||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, float dy)
|
public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, float dy)
|
||||||
{
|
{
|
||||||
|
if(scrollerBucketSize == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
if(Math.abs(dx) > Math.abs(dy))
|
if(Math.abs(dx) > Math.abs(dy))
|
||||||
getParent().requestDisallowInterceptTouchEvent(true);
|
getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
|
|
||||||
scroller.startScroll(scroller.getCurrX(), scroller.getCurrY(), (int) -dx, (int) dy, 0);
|
scroller.startScroll(scroller.getCurrX(), scroller.getCurrY(), (int) -dx, (int) dy, 0);
|
||||||
scroller.computeScrollOffset();
|
scroller.computeScrollOffset();
|
||||||
dataOffset = Math.max(0, scroller.getCurrX() / columnWidth);
|
dataOffset = Math.max(0, scroller.getCurrX() / scrollerBucketSize);
|
||||||
postInvalidate();
|
postInvalidate();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +126,7 @@ public abstract class ScrollableDataView extends View implements GestureDetector
|
|||||||
if (!scroller.isFinished())
|
if (!scroller.isFinished())
|
||||||
{
|
{
|
||||||
scroller.computeScrollOffset();
|
scroller.computeScrollOffset();
|
||||||
dataOffset = Math.max(0, scroller.getCurrX() / columnWidth);
|
dataOffset = Math.max(0, scroller.getCurrX() / scrollerBucketSize);
|
||||||
postInvalidate();
|
postInvalidate();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -147,4 +134,14 @@ public abstract class ScrollableDataView extends View implements GestureDetector
|
|||||||
scrollAnimator.cancel();
|
scrollAnimator.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getDataOffset()
|
||||||
|
{
|
||||||
|
return dataOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScrollerBucketSize(int scrollerBucketSize)
|
||||||
|
{
|
||||||
|
this.scrollerBucketSize = scrollerBucketSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/* Copyright (C) 2016 Alinson Santos Xavier
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* This program 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.PendingIntent;
|
||||||
|
import android.appwidget.AppWidgetManager;
|
||||||
|
import android.appwidget.AppWidgetProvider;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
|
import org.isoron.helpers.DialogHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
|
public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
protected abstract int getDefaultHeight();
|
||||||
|
|
||||||
|
protected abstract int getDefaultWidth();
|
||||||
|
|
||||||
|
protected abstract PendingIntent getOnClickPendingIntent(Context context, Habit habit);
|
||||||
|
|
||||||
|
protected abstract int getLayoutId();
|
||||||
|
|
||||||
|
protected abstract View buildCustomView(Context context, int max_height, int max_width,
|
||||||
|
Habit habit);
|
||||||
|
|
||||||
|
public static String getHabitIdKey(long widgetId)
|
||||||
|
{
|
||||||
|
return String.format("widget-%06d-habit", widgetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDeleted(Context context, int[] appWidgetIds)
|
||||||
|
{
|
||||||
|
Context appContext = context.getApplicationContext();
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
|
||||||
|
|
||||||
|
for(Integer id : appWidgetIds)
|
||||||
|
prefs.edit().remove(getHabitIdKey(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager,
|
||||||
|
int appWidgetId, Bundle newOptions)
|
||||||
|
{
|
||||||
|
updateWidget(context, appWidgetManager, appWidgetId, newOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdate(Context context, AppWidgetManager manager, int[] appWidgetIds)
|
||||||
|
{
|
||||||
|
for(int id : appWidgetIds)
|
||||||
|
{
|
||||||
|
Bundle options = null;
|
||||||
|
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
|
||||||
|
options = manager.getAppWidgetOptions(id);
|
||||||
|
|
||||||
|
updateWidget(context, manager, id, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateWidget(Context context, AppWidgetManager manager, int widgetId, Bundle options)
|
||||||
|
{
|
||||||
|
int maxWidth = getDefaultWidth();
|
||||||
|
int maxHeight = getDefaultHeight();
|
||||||
|
|
||||||
|
if (options != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
|
||||||
|
{
|
||||||
|
maxWidth = (int) DialogHelper.dpToPixels(context,
|
||||||
|
options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH));
|
||||||
|
maxHeight = (int) DialogHelper.dpToPixels(context,
|
||||||
|
options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT));
|
||||||
|
}
|
||||||
|
|
||||||
|
Context appContext = context.getApplicationContext();
|
||||||
|
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), getLayoutId());
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
|
||||||
|
|
||||||
|
Long habitId = prefs.getLong(getHabitIdKey(widgetId), -1L);
|
||||||
|
if(habitId < 0) return;
|
||||||
|
|
||||||
|
Habit habit = Habit.get(habitId);
|
||||||
|
View widgetView = buildCustomView(context, maxHeight, maxWidth, habit);
|
||||||
|
widgetView.setDrawingCacheEnabled(true);
|
||||||
|
widgetView.buildDrawingCache(true);
|
||||||
|
Bitmap drawingCache = widgetView.getDrawingCache();
|
||||||
|
|
||||||
|
remoteViews.setTextViewText(R.id.label, habit.name);
|
||||||
|
remoteViews.setImageViewBitmap(R.id.imageView, drawingCache);
|
||||||
|
|
||||||
|
PendingIntent onClickIntent = getOnClickPendingIntent(context, habit);
|
||||||
|
if(onClickIntent != null) remoteViews.setOnClickPendingIntent(R.id.imageView, onClickIntent);
|
||||||
|
|
||||||
|
manager.updateAppWidget(widgetId, remoteViews);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/* Copyright (C) 2016 Alinson Santos Xavier
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* This program 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.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.HabitBroadcastReceiver;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
import org.isoron.uhabits.views.CheckmarkView;
|
||||||
|
|
||||||
|
public class CheckmarkWidgetProvider extends BaseWidgetProvider
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected View buildCustomView(Context context, int maxHeight, int maxWidth, Habit habit)
|
||||||
|
{
|
||||||
|
CheckmarkView widgetView = new CheckmarkView(context);
|
||||||
|
|
||||||
|
widgetView.setHabit(habit);
|
||||||
|
widgetView.measure(maxWidth, maxHeight);
|
||||||
|
widgetView.layout(0, 0, maxWidth, maxHeight);
|
||||||
|
|
||||||
|
int width = widgetView.getMeasuredWidth();
|
||||||
|
int height = widgetView.getMeasuredHeight();
|
||||||
|
widgetView.measure(width, height);
|
||||||
|
widgetView.layout(0, 0, width, height);
|
||||||
|
|
||||||
|
return widgetView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PendingIntent getOnClickPendingIntent(Context context, Habit habit)
|
||||||
|
{
|
||||||
|
return HabitBroadcastReceiver.buildCheckIntent(context, habit, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDefaultHeight()
|
||||||
|
{
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDefaultWidth()
|
||||||
|
{
|
||||||
|
return 160;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getLayoutId()
|
||||||
|
{
|
||||||
|
return R.layout.widget_checkmark;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/* Copyright (C) 2016 Alinson Santos Xavier
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* This program 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;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.MainActivity;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
import org.isoron.uhabits.widgets.BaseWidgetProvider;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class HabitPickerDialog extends Activity implements AdapterView.OnItemClickListener
|
||||||
|
{
|
||||||
|
|
||||||
|
private Integer widgetId;
|
||||||
|
private ArrayList<Long> habitIds;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.widget_configure_activity);
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
Bundle extras = intent.getExtras();
|
||||||
|
|
||||||
|
if (extras != null) widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
|
||||||
|
AppWidgetManager.INVALID_APPWIDGET_ID);
|
||||||
|
|
||||||
|
ListView listView = (ListView) findViewById(R.id.listView);
|
||||||
|
|
||||||
|
habitIds = new ArrayList<>();
|
||||||
|
ArrayList<String> habitNames = new ArrayList<>();
|
||||||
|
|
||||||
|
List<Habit> habits = Habit.getAll(false);
|
||||||
|
for(Habit h : habits)
|
||||||
|
{
|
||||||
|
habitIds.add(h.getId());
|
||||||
|
habitNames.add(h.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayAdapter<String> adapter =
|
||||||
|
new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, habitNames);
|
||||||
|
listView.setAdapter(adapter);
|
||||||
|
listView.setOnItemClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
|
||||||
|
{
|
||||||
|
Long habitId = habitIds.get(position);
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
|
||||||
|
getApplicationContext());
|
||||||
|
prefs.edit().putLong(BaseWidgetProvider.getHabitIdKey(widgetId), habitId).commit();
|
||||||
|
|
||||||
|
MainActivity.updateWidgets(this);
|
||||||
|
|
||||||
|
Intent resultValue = new Intent();
|
||||||
|
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
|
||||||
|
setResult(RESULT_OK, resultValue);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/* Copyright (C) 2016 Alinson Santos Xavier
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* This program 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.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.isoron.helpers.DialogHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
import org.isoron.uhabits.views.HabitHistoryView;
|
||||||
|
|
||||||
|
public class HistoryWidgetProvider extends BaseWidgetProvider
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected View buildCustomView(Context context, int maxHeight, int maxWidth, Habit habit)
|
||||||
|
{
|
||||||
|
HabitHistoryView view = new HabitHistoryView(context, null);
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.measure(maxWidth, maxHeight);
|
||||||
|
view.layout(0, 0, maxWidth, maxHeight);
|
||||||
|
|
||||||
|
int width = view.getMeasuredWidth();
|
||||||
|
int height = view.getMeasuredHeight();
|
||||||
|
height -= DialogHelper.dpToPixels(context, 12);
|
||||||
|
view.measure(width, height);
|
||||||
|
view.layout(0, 0, width, height);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PendingIntent getOnClickPendingIntent(Context context, Habit habit)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDefaultHeight()
|
||||||
|
{
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDefaultWidth()
|
||||||
|
{
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getLayoutId()
|
||||||
|
{
|
||||||
|
return R.layout.widget_graph;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/* Copyright (C) 2016 Alinson Santos Xavier
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* This program 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.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.isoron.helpers.DialogHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
import org.isoron.uhabits.views.HabitScoreView;
|
||||||
|
|
||||||
|
public class ScoreWidgetProvider extends BaseWidgetProvider
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected View buildCustomView(Context context, int maxHeight, int maxWidth, Habit habit)
|
||||||
|
{
|
||||||
|
HabitScoreView view = new HabitScoreView(context, null);
|
||||||
|
view.setIsBackgroundTransparent(true);
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.measure(maxWidth, maxHeight);
|
||||||
|
view.layout(0, 0, maxWidth, maxHeight);
|
||||||
|
|
||||||
|
int width = view.getMeasuredWidth();
|
||||||
|
int height = view.getMeasuredHeight();
|
||||||
|
height -= DialogHelper.dpToPixels(context, 12);
|
||||||
|
view.measure(width, height);
|
||||||
|
view.layout(0, 0, width, height);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PendingIntent getOnClickPendingIntent(Context context, Habit habit)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDefaultHeight()
|
||||||
|
{
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDefaultWidth()
|
||||||
|
{
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getLayoutId()
|
||||||
|
{
|
||||||
|
return R.layout.widget_graph;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/* Copyright (C) 2016 Alinson Santos Xavier
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* This program 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.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.isoron.helpers.DialogHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
import org.isoron.uhabits.views.HabitScoreView;
|
||||||
|
import org.isoron.uhabits.views.HabitStreakView;
|
||||||
|
|
||||||
|
public class StreakWidgetProvider extends BaseWidgetProvider
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected View buildCustomView(Context context, int maxHeight, int maxWidth, Habit habit)
|
||||||
|
{
|
||||||
|
HabitStreakView view = new HabitStreakView(context, null);
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.measure(maxWidth, maxHeight);
|
||||||
|
view.layout(0, 0, maxWidth, maxHeight);
|
||||||
|
|
||||||
|
int width = view.getMeasuredWidth();
|
||||||
|
int height = view.getMeasuredHeight();
|
||||||
|
height -= DialogHelper.dpToPixels(context, 12);
|
||||||
|
view.measure(width, height);
|
||||||
|
view.layout(0, 0, width, height);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PendingIntent getOnClickPendingIntent(Context context, Habit habit)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDefaultHeight()
|
||||||
|
{
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDefaultWidth()
|
||||||
|
{
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getLayoutId()
|
||||||
|
{
|
||||||
|
return R.layout.widget_graph;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/src/main/res/drawable/widget_background.xml
Normal file
7
app/src/main/res/drawable/widget_background.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<solid android:color="#3fffffff" />
|
||||||
|
<corners android:radius="10dp" />
|
||||||
|
</shape>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
style="@style/habitsListStarStyle" />
|
style="@style/habitsListStarStyle" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvName"
|
android:id="@+id/label"
|
||||||
style="@style/habitsListNameStyle" />
|
style="@style/habitsListNameStyle" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
tools:context="org.isoron.uhabits.ShowHabitActivity">
|
tools:context="org.isoron.uhabits.ShowHabitActivity">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/llOverview"
|
|
||||||
style="@style/cardStyle"
|
style="@style/cardStyle"
|
||||||
android:gravity="center">
|
android:gravity="center">
|
||||||
|
|
||||||
@@ -28,10 +27,7 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout style="@style/cardStyle">
|
||||||
android:id="@+id/llStrength"
|
|
||||||
style="@style/cardStyle"
|
|
||||||
android:gravity="center">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvStrength"
|
android:id="@+id/tvStrength"
|
||||||
@@ -41,7 +37,7 @@
|
|||||||
<org.isoron.uhabits.views.HabitScoreView
|
<org.isoron.uhabits.views.HabitScoreView
|
||||||
android:id="@+id/scoreView"
|
android:id="@+id/scoreView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="200dp"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -61,7 +57,7 @@
|
|||||||
<org.isoron.uhabits.views.HabitHistoryView
|
<org.isoron.uhabits.views.HabitHistoryView
|
||||||
android:id="@+id/historyView"
|
android:id="@+id/historyView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="180dp"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -81,7 +77,7 @@
|
|||||||
<org.isoron.uhabits.views.HabitStreakView
|
<org.isoron.uhabits.views.HabitStreakView
|
||||||
android:id="@+id/streakView"
|
android:id="@+id/streakView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="200dp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
17
app/src/main/res/layout/small_widget_preview.xml
Normal file
17
app/src/main/res/layout/small_widget_preview.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="4dp">
|
||||||
|
|
||||||
|
<org.isoron.uhabits.views.CheckmarkView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
17
app/src/main/res/layout/widget_checkmark.xml
Normal file
17
app/src/main/res/layout/widget_checkmark.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="4dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
8
app/src/main/res/layout/widget_configure_activity.xml
Normal file
8
app/src/main/res/layout/widget_configure_activity.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<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">
|
||||||
|
|
||||||
|
</ListView>
|
||||||
30
app/src/main/res/layout/widget_graph.xml
Normal file
30
app/src/main/res/layout/widget_graph.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/widget_background"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingLeft="10dp"
|
||||||
|
android:paddingRight="0dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="Wake up early"
|
||||||
|
android:textColor="#3f000000"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
BIN
app/src/main/res/mipmap-hdpi/ic_small_widget_preview.png
Normal file
BIN
app/src/main/res/mipmap-hdpi/ic_small_widget_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_small_widget_preview.png
Normal file
BIN
app/src/main/res/mipmap-mdpi/ic_small_widget_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_small_widget_preview.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/ic_small_widget_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_small_widget_preview.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/ic_small_widget_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_small_widget_preview.png
Normal file
BIN
app/src/main/res/mipmap-xxxhdpi/ic_small_widget_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
13
app/src/main/res/xml/widget_checkmark_info.xml
Normal file
13
app/src/main/res/xml/widget_checkmark_info.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:minHeight="40dp"
|
||||||
|
android:minWidth="40dp"
|
||||||
|
android:initialLayout="@layout/widget_checkmark"
|
||||||
|
android:previewImage="@mipmap/ic_small_widget_preview"
|
||||||
|
android:resizeMode="none"
|
||||||
|
android:updatePeriodMillis="3600000"
|
||||||
|
android:configure="org.isoron.uhabits.widgets.HabitPickerDialog"
|
||||||
|
android:widgetCategory="home_screen">
|
||||||
|
|
||||||
|
|
||||||
|
</appwidget-provider>
|
||||||
15
app/src/main/res/xml/widget_history_info.xml
Normal file
15
app/src/main/res/xml/widget_history_info.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:minHeight="80dp"
|
||||||
|
android:minWidth="80dp"
|
||||||
|
android:minResizeWidth="40dp"
|
||||||
|
android:minResizeHeight="40dp"
|
||||||
|
android:initialLayout="@layout/widget_graph"
|
||||||
|
android:previewImage="@mipmap/ic_small_widget_preview"
|
||||||
|
android:resizeMode="vertical|horizontal"
|
||||||
|
android:updatePeriodMillis="3600000"
|
||||||
|
android:configure="org.isoron.uhabits.widgets.HabitPickerDialog"
|
||||||
|
android:widgetCategory="home_screen">
|
||||||
|
|
||||||
|
|
||||||
|
</appwidget-provider>
|
||||||
15
app/src/main/res/xml/widget_score_info.xml
Normal file
15
app/src/main/res/xml/widget_score_info.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:minHeight="80dp"
|
||||||
|
android:minWidth="80dp"
|
||||||
|
android:minResizeWidth="40dp"
|
||||||
|
android:minResizeHeight="40dp"
|
||||||
|
android:initialLayout="@layout/widget_graph"
|
||||||
|
android:previewImage="@mipmap/ic_small_widget_preview"
|
||||||
|
android:resizeMode="vertical|horizontal"
|
||||||
|
android:updatePeriodMillis="3600000"
|
||||||
|
android:configure="org.isoron.uhabits.widgets.HabitPickerDialog"
|
||||||
|
android:widgetCategory="home_screen">
|
||||||
|
|
||||||
|
|
||||||
|
</appwidget-provider>
|
||||||
14
app/src/main/res/xml/widget_streak_info.xml
Normal file
14
app/src/main/res/xml/widget_streak_info.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:minHeight="80dp"
|
||||||
|
android:minWidth="80dp"
|
||||||
|
android:minResizeWidth="40dp"
|
||||||
|
android:minResizeHeight="40dp"
|
||||||
|
android:initialLayout="@layout/widget_graph"
|
||||||
|
android:previewImage="@mipmap/ic_small_widget_preview"
|
||||||
|
android:resizeMode="vertical|horizontal"
|
||||||
|
android:updatePeriodMillis="3600000"
|
||||||
|
android:configure="org.isoron.uhabits.widgets.HabitPickerDialog"
|
||||||
|
android:widgetCategory="home_screen">
|
||||||
|
|
||||||
|
</appwidget-provider>
|
||||||
Reference in New Issue
Block a user