improve widget update behaviour

This commit is contained in:
Phillip Thelen 2016-09-30 17:31:05 +02:00
parent c044fddaea
commit 4b7c402657
11 changed files with 168 additions and 150 deletions

View file

@ -205,7 +205,7 @@
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/habit_button_widget_info" />
</receiver>
<service android:name=".widget.AvatarStatsWidgetService"/>
<service
android:name=".widget.DailiesWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" />

View file

@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="tutorial_habits">좋은 습관을 달성하고 골드와 경험치를 얻으세요! 나쁜 습관은 당신의 아바타를 다치게하니, 일상생활을 열심히 하세요!</string>
<string name="tutorial_habits">좋은 습관을 달성하고 골드와 경험치를 얻으세요! 나쁜 습관은 당신의 아바타를 다치게 하니, 일상생활을 열심히 하세요!</string>
<string name="tutorial_dailies">골드와 경험치를 위해 일일과제를 달성하세요. 주의할 점! 일일과제는 제때 끝내지 못하면 당신의 아바타를 다치게 만들어요.</string>
<string name="tutorial_todos">일상생활을 할일을 달성함으로써 골드와 경험치를 얻으세요. 경험치와 골드로 새로운 보상과 기능을 여세요!</string>
<string name="tutorial_rewards">이것들은 당신의 보상들이에요! 습관, 일일과제, 해야할 일들을 일상생활에서 달성하면 골드를 모을 수 있어요. 이 골드를 게임의 보상들이나 스스로 설정한 보상을 구입하는데 사용하세요!</string>

View file

@ -7,15 +7,19 @@
<string name="ERR_pb_barcode">데이터를 가져오지 못했습니다</string>
<!--Prefs-->
<string name="PS_settings_title">설정</string>
<string name="SP_address_hint">당신의 개인서버</string>
<string name="SP_userID_title">유저 ID</string>
<string name="SP_userID_summary">당신의 유저ID</string>
<string name="SP_address_hint">당신의 사용자 지정 서버</string>
<string name="SP_userID_title">사용자 ID</string>
<string name="SP_userID_summary">당신의 사용자 ID</string>
<string name="SP_APIToken_title">API 토큰</string>
<string name="SP_APIToken_summary">당신의 API 토큰</string>
<string name="Language_title">언어</string>
<string name="Language_summary">Habitica의 언어 바꾸기</string>
<string name="SP_user_qr_code">당신의 QR코드</string>
<string name="PS_contact_title">연락처</string>
<string name="unknown_error">오류가 발생했습니다...</string>
<string name="pref_account_header">계정</string>
<string name="pref_first_day_of_the_week_title">주의 첫날</string>
<string name="pref_first_day_of_the_week_summary">모든 캘린더에서 주의 첫날</string>
<string name="pref_reminder_header">매일 알림</string>
<string name="pref_reminder_checkbox">알림 활성화</string>
<string name="pref_reminder_picker">알림 시간 설정</string>
@ -24,6 +28,11 @@
<string name="preference_push_you_won_challenge">도전 기회를 얻었습니다.</string>
<string name="preference_push_received_a_private_message">개인 메시지를 받았습니다.</string>
<string name="preference_push_gifted_gems">선물받은 젬</string>
<string name="preference_push_gifted_subscription">선물 받은 구독</string>
<string name="preference_push_invited_to_party">파티에 초대 받음</string>
<string name="preference_push_invited_to_guild">길드에 초대 받음</string>
<string name="preference_push_your_quest_has_begun">퀘스트가 시작되었음</string>
<string name="preference_push_invited_to_quest">퀘스트에 초대를 받았음</string>
<!--Adding tasks-->
<string name="task_value"></string>
<string name="new_todo">새로운 할 일</string>
@ -235,6 +244,7 @@
<string name="privacy">사생활 보호</string>
<string name="write_message">메세지 작성</string>
<string name="post">게시</string>
<string name="guild_search_hint">길드 검색</string>
<string name="todo_due" formatted="false">만기: %s</string>
<string name="daily_streak" formatted="false">연속 달성: %d</string>
<string name="todo_has_duedate">과제가 만기일이 있습니다</string>
@ -337,5 +347,31 @@
<string name="open_in_store">플레이스토어로 열기</string>
<string name="change_class_confirmation">보석 3개를 사용하여 클레스를 바꾸시겠습니까? </string>
<string name="leaderMessage" formatted="false">%1$s로부터 온 메세지</string>
<string name="confirm">확인</string>
<string name="market">시장</string>
<string name="timeTravelers">시간 여행자들</string>
<string name="seasonalShop">계절 상점</string>
<string name="empty_inbox">받은 편지함 메시지가 없습니다. 공개 채팅 메시지를 통해 사용자에게 새 메시지를 보낼 수 있습니다!</string>
<string name="party_invite">친구를 초대하여 잠금 해제하기</string>
<string name="no_gold">골드가 충분하지 않음</string>
<string name="no_potion">체력 물약을 살 필요가 없음</string>
<string name="successful_purchase" formatted="false">%1$s을(를) 성공적으로 구매했음</string>
<string name="purchase_confirmation_title">구매 확인</string>
<string name="confirm_purchase_text" formatted="false">%1$s을(를) %2$s %3$s(으)로 구매함</string>
<string name="gem">보석</string>
<string name="hourglass">모래시계</string>
<string name="hourglasses">모래시계</string>
<string name="gold_singular">골드</string>
<string name="gold_plural">골드</string>
<string name="chat_message_copied">메시지를 클립보드에 복사했음</string>
<string name="copy_chat_message">클립보드로 복사함</string>
<string name="edit_tag_title">태그 편집</string>
<string name="edit_tag_btn_edit">편집</string>
<string name="edit_tag_btn_done">완료</string>
<string name="edit_tag_btn_delete">삭제</string>
<string name="confirm_delete_tag_title">정말이요?</string>
<string name="confirm_delete_tag_message">정말 삭제할까요?</string>
<string name="filter_drawer_edit_tags">태그 편집</string>
<string name="filter_drawer_filter_tags">태그로 정렬</string>
<!--QR Strings-->
</resources>

View file

@ -413,5 +413,6 @@ To start, which parts of your life do you want to improve?</string>
<string name="widget_habit_button">Habitica Do Habit</string>
<string name="widget_dailies">Habitica Dailies</string>
<string name="widget_add_task">Habitica Add Task</string>
<string name="google_services_missing">Google play services could not be found.</string>
</resources>

View file

@ -54,7 +54,7 @@ import com.habitrpg.android.habitica.ui.fragments.social.party.PartyInviteFragme
import com.habitrpg.android.habitica.ui.fragments.social.party.PartyMemberListFragment;
import com.habitrpg.android.habitica.ui.fragments.tasks.TaskRecyclerViewFragment;
import com.habitrpg.android.habitica.ui.fragments.tasks.TasksFragment;
import com.habitrpg.android.habitica.widget.AvatarStatsWidgetService;
import com.habitrpg.android.habitica.widget.AvatarStatsWidgetProvider;
import com.habitrpg.android.habitica.widget.DailiesWidgetProvider;
import com.habitrpg.android.habitica.widget.HabitButtonWidgetProvider;
import com.habitrpg.android.habitica.widget.HabitButtonWidgetService;
@ -66,7 +66,6 @@ import dagger.Component;
@Singleton
@Component(modules = {AppModule.class, ApiModule.class})
public interface AppComponent {
void inject(AvatarStatsWidgetService target);
void inject(ClassSelectionActivity classSelectionActivity);
@ -177,4 +176,6 @@ public interface AppComponent {
void inject(HabitButtonWidgetActivity habitButtonWidgetActivity);
void inject(HabitButtonWidgetProvider habitButtonWidgetProvider);
void inject(AvatarStatsWidgetProvider avatarStatsWidgetProvider);
}

View file

@ -38,6 +38,7 @@ import org.json.JSONObject;
import android.accounts.AccountManager;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
@ -45,6 +46,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.PreferenceManager;
import android.text.SpannableString;
import android.text.style.UnderlineSpan;
@ -414,7 +416,16 @@ public class LoginActivity extends BaseActivity
String[] accountTypes = new String[]{"com.google"};
Intent intent = AccountPicker.newChooseAccountIntent(null, null,
accountTypes, false, null, null, null, null);
startActivityForResult(intent, REQUEST_CODE_PICK_ACCOUNT);
try {
startActivityForResult(intent, REQUEST_CODE_PICK_ACCOUNT);
} catch (ActivityNotFoundException e) {
Dialog dialog = new AlertDialog.Builder(this)
.setTitle(R.string.authentication_error_title)
.setMessage(R.string.google_services_missing)
.setNegativeButton(R.string.close, (dialogInterface, i) -> dialogInterface.dismiss())
.create();
dialog.show();
}
}
private void handleGoogleLoginResult() {
@ -423,12 +434,9 @@ public class LoginActivity extends BaseActivity
Observable.defer(() -> {
try {
return Observable.just(GoogleAuthUtil.getToken(LoginActivity.this, googleEmail, scopes));
} catch (IOException e) {
throw Exceptions.propagate(e);
} catch (GoogleAuthException e) {
} catch (IOException | GoogleAuthException e) {
throw Exceptions.propagate(e);
}
})
.flatMap(token -> apiHelper.connectSocial("google", googleEmail, token))
.compose(apiHelper.configureApiCallObserver())

View file

@ -1,8 +1,20 @@
package com.habitrpg.android.habitica.widget;
import com.habitrpg.android.habitica.APIHelper;
import com.habitrpg.android.habitica.HabiticaApplication;
import com.habitrpg.android.habitica.HostConfig;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.ui.AvatarView;
import com.habitrpg.android.habitica.ui.activities.MainActivity;
import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
import com.magicmicky.habitrpgwrapper.lib.models.Stats;
import com.raizlabs.android.dbflow.runtime.transaction.BaseTransaction;
import com.raizlabs.android.dbflow.runtime.transaction.TransactionListener;
import com.raizlabs.android.dbflow.sql.builder.Condition;
import com.raizlabs.android.dbflow.sql.language.Select;
import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
@ -14,35 +26,39 @@ import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
import javax.inject.Inject;
public class AvatarStatsWidgetProvider extends BaseWidgetProvider {
private static final String LOG = AvatarStatsWidgetProvider.class.getName();
private AppWidgetManager appWidgetManager;
@Override
public int layoutResourceId() {
return R.layout.widget_avatar_stats;
}
@Inject
APIHelper apiHelper;
@Inject
HostConfig hostConfig;
private void setUp(Context context) {
if (apiHelper == null) {
HabiticaApplication application = HabiticaApplication.getInstance(context);
application.getComponent().inject(this);
}
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// Get all ids
this.setUp(context);
this.appWidgetManager = appWidgetManager;
this.context = context;
ComponentName thisWidget = new ComponentName(context,
AvatarStatsWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
if (Build.VERSION.SDK_INT >= 16) {
for (int widgetId : allWidgetIds) {
Bundle options = appWidgetManager.getAppWidgetOptions(widgetId);
appWidgetManager.partiallyUpdateAppWidget(widgetId,
sizeRemoteViews(context, options, widgetId));
}
}
// Build the intent to call the service
Intent intent = new Intent(context.getApplicationContext(),
AvatarStatsWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
context.startService(intent);
new Select().from(HabitRPGUser.class).where(Condition.column("id").eq(hostConfig.getUser())).async().querySingle(userTransactionListener);
}
@ -64,4 +80,75 @@ public class AvatarStatsWidgetProvider extends BaseWidgetProvider {
return remoteViews;
}
private TransactionListener<HabitRPGUser> userTransactionListener = new TransactionListener<HabitRPGUser>() {
@Override
public void onResultReceived(HabitRPGUser habitRPGUser) {
updateData(habitRPGUser);
}
@Override
public boolean onReady(BaseTransaction<HabitRPGUser> baseTransaction) {
return true;
}
@Override
public boolean hasResult(BaseTransaction<HabitRPGUser> baseTransaction, HabitRPGUser habitRPGUser) {
return true;
}
};
private void updateData(HabitRPGUser user) {
if (user == null || user.getStats() == null) {
return;
}
Stats stats = user.getStats();
ComponentName thisWidget = new ComponentName(context, AvatarStatsWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
String healthValueString = "" + stats.getHp().intValue() + "/" + stats.getMaxHealth();
String expValueString = "" + stats.getExp().intValue() + "/" + stats.getToNextLevel();
String mpValueString = "" + stats.getMp().intValue() + "/" + stats.getMaxMP();
for (int widgetId : allWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_avatar_stats);
remoteViews.setTextViewText(R.id.TV_hp_value, healthValueString);
remoteViews.setTextViewText(R.id.exp_TV_value, expValueString);
remoteViews.setTextViewText(R.id.mp_TV_value, mpValueString);
remoteViews.setProgressBar(R.id.hp_bar, stats.getMaxHealth(), stats.getHp().intValue(), false);
remoteViews.setProgressBar(R.id.exp_bar, stats.getToNextLevel(), stats.getExp().intValue(), false);
remoteViews.setProgressBar(R.id.mp_bar, stats.getMaxMP(), stats.getMp().intValue(), false);
remoteViews.setViewVisibility(R.id.mp_wrapper, (stats.get_class() == null || stats.getLvl() < 10 || user.getPreferences().getDisableClasses()) ? View.GONE : View.VISIBLE);
int gp = (stats.getGp().intValue());
int sp = (int) ((stats.getGp() - gp) * 100);
remoteViews.setTextViewText(R.id.gold_tv, String.valueOf(gp));
remoteViews.setTextViewText(R.id.silver_tv, String.valueOf(sp));
remoteViews.setTextViewText(R.id.gems_tv, String.valueOf((int) (user.getBalance() * 4)));
remoteViews.setTextViewText(R.id.lvl_tv, context.getString(R.string.user_level, user.getStats().getLvl().toString()));
AvatarView avatarView = new AvatarView(context, true, true, true);
;
avatarView.setUser(user);
RemoteViews finalRemoteViews = remoteViews;
avatarView.onAvatarImageReady(bitmap -> {
finalRemoteViews.setImageViewBitmap(R.id.avatar_view, bitmap);
appWidgetManager.partiallyUpdateAppWidget(allWidgetIds, finalRemoteViews);
});
//If user click on life and xp: open the app
Intent openAppIntent = new Intent(context.getApplicationContext(), MainActivity.class);
PendingIntent openApp = PendingIntent.getActivity(context, 0, openAppIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.widget_main_view, openApp);
if (Build.VERSION.SDK_INT >= 16) {
Bundle options = appWidgetManager.getAppWidgetOptions(widgetId);
remoteViews = sizeRemoteViews(context, options, widgetId);
}
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
}

View file

@ -1,115 +0,0 @@
package com.habitrpg.android.habitica.widget;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.view.View;
import android.widget.RemoteViews;
import com.habitrpg.android.habitica.HabiticaApplication;
import com.habitrpg.android.habitica.HostConfig;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.ui.AvatarView;
import com.habitrpg.android.habitica.ui.activities.MainActivity;
import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
import com.magicmicky.habitrpgwrapper.lib.models.Stats;
import com.raizlabs.android.dbflow.runtime.transaction.BaseTransaction;
import com.raizlabs.android.dbflow.runtime.transaction.TransactionListener;
import com.raizlabs.android.dbflow.sql.builder.Condition;
import com.raizlabs.android.dbflow.sql.language.Select;
import javax.inject.Inject;
public class AvatarStatsWidgetService extends Service {
private static final String LOG = ".avatarwidget.service";
@Inject
public HostConfig hostConfig;
private AppWidgetManager appWidgetManager;
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
HabiticaApplication application = (HabiticaApplication) getApplication();
application.getComponent().inject(this);
this.appWidgetManager = AppWidgetManager.getInstance(this);
new Select().from(HabitRPGUser.class).where(Condition.column("id").eq(hostConfig.getUser())).async().querySingle(userTransactionListener);
stopSelf();
return START_STICKY;
}
private TransactionListener<HabitRPGUser> userTransactionListener = new TransactionListener<HabitRPGUser>() {
@Override
public void onResultReceived(HabitRPGUser habitRPGUser) {
updateData(habitRPGUser);
}
@Override
public boolean onReady(BaseTransaction<HabitRPGUser> baseTransaction) {
return true;
}
@Override
public boolean hasResult(BaseTransaction<HabitRPGUser> baseTransaction, HabitRPGUser habitRPGUser) {
return true;
}
};
private void updateData(HabitRPGUser user) {
if (user == null || user.getStats() == null) {
return;
}
Stats stats = user.getStats();
ComponentName thisWidget = new ComponentName(this, AvatarStatsWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
String healthValueString = "" + stats.getHp().intValue() + "/" + stats.getMaxHealth();
String expValueString = "" + stats.getExp().intValue() + "/" + stats.getToNextLevel();
String mpValueString = "" + stats.getMp().intValue() + "/" + stats.getMaxMP();
RemoteViews remoteViews = new RemoteViews(this.getPackageName(), R.layout.widget_avatar_stats);
remoteViews.setTextViewText(R.id.TV_hp_value, healthValueString);
remoteViews.setTextViewText(R.id.exp_TV_value, expValueString);
remoteViews.setTextViewText(R.id.mp_TV_value, mpValueString);
remoteViews.setProgressBar(R.id.hp_bar, stats.getMaxHealth(), stats.getHp().intValue(), false);
remoteViews.setProgressBar(R.id.exp_bar, stats.getToNextLevel(), stats.getExp().intValue(), false);
remoteViews.setProgressBar(R.id.mp_bar, stats.getMaxMP(), stats.getMp().intValue(), false);
remoteViews.setViewVisibility(R.id.mp_wrapper, (stats.get_class() == null || stats.getLvl() < 10 || user.getPreferences().getDisableClasses()) ? View.GONE : View.VISIBLE);
int gp = (stats.getGp().intValue());
int sp = (int) ((stats.getGp() - gp) * 100);
remoteViews.setTextViewText(R.id.gold_tv, String.valueOf(gp));
remoteViews.setTextViewText(R.id.silver_tv, String.valueOf(sp));
remoteViews.setTextViewText(R.id.gems_tv, String.valueOf((int)(user.getBalance() * 4)));
remoteViews.setTextViewText(R.id.lvl_tv, getString(R.string.user_level, user.getStats().getLvl()));
AvatarView avatarView = new AvatarView(this, true, true, true);;
avatarView.setUser(user);
avatarView.onAvatarImageReady(bitmap -> {
remoteViews.setImageViewBitmap(R.id.avatar_view, bitmap);
appWidgetManager.partiallyUpdateAppWidget(allWidgetIds, remoteViews);
});
//If user click on life and xp: open the app
Intent openAppIntent = new Intent(this.getApplicationContext(), MainActivity.class);
PendingIntent openApp = PendingIntent.getActivity(this, 0, openAppIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.widget_main_view, openApp);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
appWidgetManager.partiallyUpdateAppWidget(allWidgetIds, remoteViews);
} else {
appWidgetManager.updateAppWidget(allWidgetIds, remoteViews);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

View file

@ -45,7 +45,9 @@ public class DailiesListProvider implements RemoteViewsService.RemoteViewsFactor
taskList = tasks;
this.reloadData = false;
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(widgetId, R.id.list_view);
}, throwable -> {});
}, throwable -> {
this.reloadData = false;
});
}

View file

@ -94,11 +94,9 @@ public class DailiesWidgetProvider extends BaseWidgetProvider {
PendingIntent.FLAG_UPDATE_CURRENT);
rv.setPendingIntentTemplate(R.id.list_view, toastPendingIntent);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
appWidgetManager.partiallyUpdateAppWidget(appWidgetIds[i], rv);
} else {
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(appWidgetIds[i], R.id.list_view);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
@ -112,4 +110,4 @@ public class DailiesWidgetProvider extends BaseWidgetProvider {
public RemoteViews configureRemoteViews(RemoteViews remoteViews, int widgetId, int columns, int rows) {
return remoteViews;
}
}
}

View file

@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="store_short_description">게임처럼 당신의 인생을 치료 동기 부여 및 조직 유지 합니다!</string>
<string name="store_short_description">인생을 게임처럼 다루어서 동기를 부여하고 체계를 잡으세요!</string>
<string name="store_description">HabitRPG 에서NEW 앱 ! 부드러운 경험과 더 features.
에 대해 처음부터 다시 작성