mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
Simplify StackWidgetService; reduce flicker
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.widgets
|
||||
|
||||
import android.content.*
|
||||
import android.view.*
|
||||
import org.isoron.uhabits.widgets.views.*
|
||||
|
||||
class EmptyWidget(
|
||||
context: Context,
|
||||
widgetId: Int
|
||||
) : BaseWidget(context, widgetId) {
|
||||
|
||||
override fun getOnClickPendingIntent(context: Context) = null
|
||||
override fun refreshData(v: View) {}
|
||||
override fun buildView() = EmptyWidgetView(context)
|
||||
override fun getDefaultHeight() = 200
|
||||
override fun getDefaultWidth() = 200
|
||||
}
|
||||
@@ -52,7 +52,6 @@ class StackWidget(
|
||||
serviceIntent.data = Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME))
|
||||
remoteViews.setRemoteAdapter(StackWidgetType.getStackWidgetAdapterViewId(widgetType), serviceIntent)
|
||||
manager.notifyAppWidgetViewDataChanged(id, StackWidgetType.getStackWidgetAdapterViewId(widgetType))
|
||||
// TODO what should the empty view look like?
|
||||
remoteViews.setEmptyView(StackWidgetType.getStackWidgetAdapterViewId(widgetType),
|
||||
StackWidgetType.getStackWidgetEmptyViewId(widgetType))
|
||||
return remoteViews
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.appwidget.*;
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import android.support.annotation.*;
|
||||
import android.util.Log;
|
||||
import android.widget.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
@@ -33,14 +34,14 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
|
||||
private Context context;
|
||||
private int widgetId;
|
||||
private long[] habitIds;
|
||||
private ArrayList<Habit> habits = new ArrayList<>();
|
||||
private StackWidgetType widgetType;
|
||||
private ArrayList<RemoteViews> remoteViews = new ArrayList<>();
|
||||
|
||||
public StackRemoteViewsFactory(Context context, Intent intent)
|
||||
{
|
||||
this.context = context;
|
||||
widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
|
||||
AppWidgetManager.INVALID_APPWIDGET_ID);
|
||||
AppWidgetManager.INVALID_APPWIDGET_ID);
|
||||
int widgetTypeValue = intent.getIntExtra(WIDGET_TYPE, -1);
|
||||
String habitIdsStr = intent.getStringExtra(HABIT_IDS);
|
||||
|
||||
@@ -63,76 +64,30 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
|
||||
|
||||
public int getCount()
|
||||
{
|
||||
return habits.size();
|
||||
return habitIds.length;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public WidgetDimensions getDimensionsFromOptions(@NonNull Context ctx,
|
||||
@NonNull Bundle options)
|
||||
{
|
||||
int maxWidth =
|
||||
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_WIDTH));
|
||||
int maxHeight =
|
||||
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_HEIGHT));
|
||||
int minWidth =
|
||||
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_WIDTH));
|
||||
int minHeight =
|
||||
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_HEIGHT));
|
||||
int maxWidth = (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_WIDTH));
|
||||
int maxHeight = (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_HEIGHT));
|
||||
int minWidth = (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_WIDTH));
|
||||
int minHeight = (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_HEIGHT));
|
||||
|
||||
return new WidgetDimensions(minWidth, maxHeight, maxWidth, minHeight);
|
||||
}
|
||||
|
||||
public RemoteViews getViewAt(int position)
|
||||
{
|
||||
RemoteViews rv = null;
|
||||
if (position < getCount())
|
||||
{
|
||||
Habit habit = habits.get(position);
|
||||
BaseWidget widget = initializeWidget(habit);
|
||||
Bundle options =
|
||||
AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId);
|
||||
widget.setDimensions(getDimensionsFromOptions(context, options));
|
||||
final RemoteViews[] landscape = new RemoteViews[1];
|
||||
final RemoteViews[] portrait = new RemoteViews[1];
|
||||
|
||||
Object lock = new Object();
|
||||
final boolean[] flag = {false};
|
||||
|
||||
new Handler(Looper.getMainLooper()).post(() ->
|
||||
{
|
||||
synchronized (lock)
|
||||
{
|
||||
landscape[0] =
|
||||
widget.getLandscapeRemoteViews();
|
||||
portrait[0] =
|
||||
widget.getPortraitRemoteViews();
|
||||
flag[0] = true;
|
||||
lock.notifyAll();
|
||||
}
|
||||
});
|
||||
|
||||
synchronized (lock)
|
||||
{
|
||||
while (!flag[0])
|
||||
{
|
||||
try
|
||||
{
|
||||
lock.wait();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rv = new RemoteViews(landscape[0], portrait[0]);
|
||||
}
|
||||
|
||||
return rv;
|
||||
Log.i("StackRemoteViewsFactory", "getViewAt " + position);
|
||||
if (position < 0 || position > remoteViews.size()) return null;
|
||||
return remoteViews.get(position);
|
||||
}
|
||||
|
||||
private BaseWidget initializeWidget(Habit habit)
|
||||
@NonNull
|
||||
private BaseWidget constructWidget(@NonNull Habit habit)
|
||||
{
|
||||
switch (widgetType)
|
||||
{
|
||||
@@ -147,12 +102,18 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
|
||||
case STREAKS:
|
||||
return new StreakWidget(context, widgetId, habit);
|
||||
}
|
||||
return null;
|
||||
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public RemoteViews getLoadingView()
|
||||
{
|
||||
return null;
|
||||
Bundle options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId);
|
||||
EmptyWidget widget = new EmptyWidget(context, widgetId);
|
||||
widget.setDimensions(getDimensionsFromOptions(context, options));
|
||||
RemoteViews landscapeViews = widget.getLandscapeRemoteViews();
|
||||
RemoteViews portraitViews = widget.getPortraitRemoteViews();
|
||||
return new RemoteViews(landscapeViews, portraitViews);
|
||||
}
|
||||
|
||||
public int getViewTypeCount()
|
||||
@@ -162,25 +123,41 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
|
||||
|
||||
public long getItemId(int position)
|
||||
{
|
||||
return position;
|
||||
return habitIds[position];
|
||||
}
|
||||
|
||||
public boolean hasStableIds()
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onDataSetChanged()
|
||||
{
|
||||
habits.clear();
|
||||
Log.i("StackRemoteViewsFactory", "onDataSetChanged started");
|
||||
|
||||
HabitsApplication app = (HabitsApplication) context.getApplicationContext();
|
||||
HabitList habitList = app.getComponent().getHabitList();
|
||||
Bundle options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId);
|
||||
ArrayList<RemoteViews> newRemoteViews = new ArrayList<>();
|
||||
|
||||
if (Looper.myLooper() == null) Looper.prepare();
|
||||
|
||||
for (long id : habitIds)
|
||||
{
|
||||
Habit h = habitList.getById(id);
|
||||
if (h == null) throw new HabitNotFoundException();
|
||||
habits.add(h);
|
||||
|
||||
BaseWidget widget = constructWidget(h);
|
||||
widget.setDimensions(getDimensionsFromOptions(context, options));
|
||||
|
||||
RemoteViews landscapeViews = widget.getLandscapeRemoteViews();
|
||||
RemoteViews portraitViews = widget.getPortraitRemoteViews();
|
||||
newRemoteViews.add(new RemoteViews(landscapeViews, portraitViews));
|
||||
|
||||
Log.i("StackRemoteViewsFactory", "onDataSetChanged constructed widget " + id);
|
||||
}
|
||||
|
||||
remoteViews = newRemoteViews;
|
||||
Log.i("StackRemoteViewsFactory", "onDataSetChanged ended");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.widgets.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.isoron.uhabits.R;
|
||||
|
||||
public class EmptyWidgetView extends HabitWidgetView
|
||||
{
|
||||
|
||||
private TextView title;
|
||||
|
||||
public EmptyWidgetView(Context context)
|
||||
{
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public void setTitle(String text)
|
||||
{
|
||||
title.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected Integer getInnerLayoutId()
|
||||
{
|
||||
return R.layout.widget_graph;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
title = (TextView) findViewById(R.id.title);
|
||||
title.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
50
uhabits-android/src/main/res/layout/widget_empty.xml
Normal file
50
uhabits-android/src/main/res/layout/widget_empty.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
~
|
||||
~ This file is part of Loop Habit Tracker.
|
||||
~
|
||||
~ Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by the
|
||||
~ Free Software Foundation, either version 3 of the License, or (at your
|
||||
~ option) any later version.
|
||||
~
|
||||
~ Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
~ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
~ more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<FrameLayout
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/frame"
|
||||
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">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/innerFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingBottom="4dp"
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/white"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
Reference in New Issue
Block a user