diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/MathHelper.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/MathHelper.java new file mode 100644 index 000000000..b7160c9b1 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/MathHelper.java @@ -0,0 +1,7 @@ +package com.habitrpg.android.habitica.helpers; + +public class MathHelper { + static public Double round(Double value, int n) { + return (Math.round(value * Math.pow(10, n))) / (Math.pow(10, n)); + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/CheckClassSelectionUseCase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/CheckClassSelectionUseCase.java new file mode 100644 index 000000000..ae72109f0 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/CheckClassSelectionUseCase.java @@ -0,0 +1,78 @@ +package com.habitrpg.android.habitica.interactors; + +import android.content.Intent; +import android.os.Bundle; + +import com.habitrpg.android.habitica.HabiticaApplication; +import com.habitrpg.android.habitica.events.SelectClassEvent; +import com.habitrpg.android.habitica.executors.PostExecutionThread; +import com.habitrpg.android.habitica.executors.ThreadExecutor; +import com.habitrpg.android.habitica.ui.activities.ClassSelectionActivity; +import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser; + +import javax.inject.Inject; + +import rx.Observable; + +import static com.habitrpg.android.habitica.ui.activities.MainActivity.SELECT_CLASS_RESULT; + +public class CheckClassSelectionUseCase extends UseCase { + @Inject + public CheckClassSelectionUseCase(ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) { + super(threadExecutor, postExecutionThread); + } + + @Override + protected Observable buildUseCaseObservable(RequestValues requestValues) { + return Observable.from(() -> { + + HabitRPGUser user = requestValues.user; + + if(requestValues.selectClassEvent == null) { + if (user.getStats().getLvl() > 10 && + !user.getPreferences().getDisableClasses() && + !user.getFlags().getClassSelected()) { + SelectClassEvent event = new SelectClassEvent(); + event.isInitialSelection = true; + event.currentClass = user.getStats().get_class().toString(); + displayClassSelectionActivity(user, event); + } + } else { + displayClassSelectionActivity(user, requestValues.selectClassEvent); + } + + return null; + }); + } + + private void displayClassSelectionActivity(HabitRPGUser user, SelectClassEvent event) { + Bundle bundle = new Bundle(); + bundle.putString("size", user.getPreferences().getSize()); + bundle.putString("skin", user.getPreferences().getSkin()); + bundle.putString("shirt", user.getPreferences().getShirt()); + bundle.putInt("hairBangs", user.getPreferences().getHair().getBangs()); + bundle.putInt("hairBase", user.getPreferences().getHair().getBase()); + bundle.putString("hairColor", user.getPreferences().getHair().getColor()); + bundle.putInt("hairMustache", user.getPreferences().getHair().getMustache()); + bundle.putInt("hairBeard", user.getPreferences().getHair().getBeard()); + bundle.putBoolean("isInitialSelection", event.isInitialSelection); + bundle.putString("currentClass", event.currentClass); + + Intent intent = new Intent(HabiticaApplication.currentActivity, ClassSelectionActivity.class); + intent.putExtras(bundle); + HabiticaApplication.currentActivity.startActivityForResult(intent, SELECT_CLASS_RESULT); + } + + public static final class RequestValues implements UseCase.RequestValues { + + + private HabitRPGUser user; + private SelectClassEvent selectClassEvent; + + public RequestValues(HabitRPGUser user, SelectClassEvent selectClassEvent) { + + this.user = user; + this.selectClassEvent = selectClassEvent; + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DailyCheckUseCase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DailyCheckUseCase.java index 77909df7d..61a8c0917 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DailyCheckUseCase.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DailyCheckUseCase.java @@ -25,7 +25,7 @@ public class DailyCheckUseCase extends UseCase buildUseCaseObservable(DailyCheckUseCase.RequestValues requestValues) { + protected Observable buildUseCaseObservable(RequestValues requestValues) { return taskRepository.taskChecked(requestValues.task, requestValues.Up).doOnNext(res -> { soundManager.loadAndPlayAudio(SoundManager.SoundDaily); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.java new file mode 100644 index 000000000..978d8af73 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.java @@ -0,0 +1,61 @@ +package com.habitrpg.android.habitica.interactors; + +import android.os.Handler; +import android.support.v7.app.AppCompatActivity; +import android.view.View; + +import com.habitrpg.android.habitica.executors.PostExecutionThread; +import com.habitrpg.android.habitica.executors.ThreadExecutor; +import com.habitrpg.android.habitica.helpers.SoundManager; +import com.habitrpg.android.habitica.ui.helpers.UiUtils; +import com.magicmicky.habitrpgwrapper.lib.models.TaskDirectionData; + +import javax.inject.Inject; + +import rx.Observable; + +import static com.habitrpg.android.habitica.ui.helpers.UiUtils.showSnackbar; + +public class DisplayItemDropUseCase extends UseCase { + + private SoundManager soundManager; + + @Inject + public DisplayItemDropUseCase(SoundManager soundManager, ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) { + super(threadExecutor, postExecutionThread); + this.soundManager = soundManager; + } + + @Override + protected Observable buildUseCaseObservable(RequestValues requestValues) { + return Observable.from(() -> { + TaskDirectionData data = requestValues.data; + + if (data.get_tmp() != null) { + if (data.get_tmp().getDrop() != null) { + new Handler().postDelayed(() -> { + showSnackbar(requestValues.context, requestValues.snackbarTargetView, + data.get_tmp().getDrop().getDialog(), UiUtils.SnackbarDisplayType.DROP); + soundManager.loadAndPlayAudio(SoundManager.SoundItemDrop); + }, 3000L); + + } + } + + return null; + }); + } + + public static final class RequestValues implements UseCase.RequestValues { + + private TaskDirectionData data; + private AppCompatActivity context; + private View snackbarTargetView; + + public RequestValues(TaskDirectionData data, AppCompatActivity context, View snackbarTargetView) { + this.data = data; + this.context = context; + this.snackbarTargetView = snackbarTargetView; + } + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.java new file mode 100644 index 000000000..dacc46853 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.java @@ -0,0 +1,104 @@ +package com.habitrpg.android.habitica.interactors; + +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.TextView; + +import com.habitrpg.android.habitica.R; +import com.habitrpg.android.habitica.events.ShareEvent; +import com.habitrpg.android.habitica.executors.PostExecutionThread; +import com.habitrpg.android.habitica.executors.ThreadExecutor; +import com.habitrpg.android.habitica.helpers.SoundManager; +import com.habitrpg.android.habitica.ui.AvatarView; +import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser; +import com.magicmicky.habitrpgwrapper.lib.models.SuppressedModals; + +import org.greenrobot.eventbus.EventBus; + +import javax.inject.Inject; + +import rx.Observable; + +public class LevelUpUseCase extends UseCase { + + private SoundManager soundManager; + private CheckClassSelectionUseCase checkClassSelectionUseCase; + + @Inject + public LevelUpUseCase(SoundManager soundManager, ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread, + CheckClassSelectionUseCase checkClassSelectionUseCase) { + super(threadExecutor, postExecutionThread); + this.soundManager = soundManager; + this.checkClassSelectionUseCase = checkClassSelectionUseCase; + } + + @Override + protected Observable buildUseCaseObservable(RequestValues requestValues) { + return Observable.from(() -> { + soundManager.loadAndPlayAudio(SoundManager.SoundLevelUp); + + + SuppressedModals suppressedModals = requestValues.user.getPreferences().getSuppressModals(); + if (suppressedModals != null) { + if (suppressedModals.getLevelUp()) { + checkClassSelectionUseCase.observable(new CheckClassSelectionUseCase.RequestValues(requestValues.user, null)) + .subscribe(aVoid -> { + }, throwable -> { + }); + + return null; + } + } + + View customView = requestValues.compatActivity.getLayoutInflater().inflate(R.layout.dialog_levelup, null); + if (customView != null) { + TextView detailView = (TextView) customView.findViewById(R.id.levelupDetail); + detailView.setText(requestValues.compatActivity.getString(R.string.levelup_detail, requestValues.newLevel)); + AvatarView dialogAvatarView = (AvatarView) customView.findViewById(R.id.avatarView); + dialogAvatarView.setUser(requestValues.user); + } + + final ShareEvent event = new ShareEvent(); + event.sharedMessage = requestValues.compatActivity.getString(R.string.share_levelup, requestValues.newLevel + "") + " https://habitica.com/social/level-up"; + AvatarView avatarView = new AvatarView(requestValues.compatActivity, true, true, true); + avatarView.setUser(requestValues.user); + avatarView.onAvatarImageReady(avatarImage -> event.shareImage = avatarImage); + + AlertDialog alert = new AlertDialog.Builder(requestValues.compatActivity) + .setTitle(R.string.levelup_header) + .setView(customView) + .setPositiveButton(R.string.levelup_button, (dialog, which) -> { + checkClassSelectionUseCase.observable(new CheckClassSelectionUseCase.RequestValues(requestValues.user, null)) + .subscribe(aVoid -> { + }, throwable -> { + }); + }) + .setNeutralButton(R.string.share, (dialog, which) -> { + EventBus.getDefault().post(event); + dialog.dismiss(); + }) + .create(); + + if (!requestValues.compatActivity.isFinishing()) { + alert.show(); + } + + return null; + + }); + } + + public static final class RequestValues implements UseCase.RequestValues { + private HabitRPGUser user; + private int newLevel; + private AppCompatActivity compatActivity; + + public RequestValues(HabitRPGUser user, int newLevel, AppCompatActivity compatActivity) { + + this.user = user; + this.newLevel = newLevel; + this.compatActivity = compatActivity; + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.java new file mode 100644 index 000000000..72135ef9a --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.java @@ -0,0 +1,112 @@ +package com.habitrpg.android.habitica.interactors; + +import android.support.v4.util.Pair; +import android.support.v7.app.AppCompatActivity; +import android.view.View; + +import com.habitrpg.android.habitica.executors.PostExecutionThread; +import com.habitrpg.android.habitica.executors.ThreadExecutor; +import com.habitrpg.android.habitica.ui.helpers.UiUtils; +import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser; +import com.magicmicky.habitrpgwrapper.lib.models.Stats; + +import javax.inject.Inject; + +import rx.Observable; +import rx.functions.Action0; + +import static com.habitrpg.android.habitica.helpers.MathHelper.round; +import static com.habitrpg.android.habitica.ui.helpers.UiUtils.showSnackbar; + +public class NotifyUserUseCase extends UseCase { + + public static final int MIN_LEVEL_FOR_SKILLS = 11; + private LevelUpUseCase levelUpUseCase; + + @Inject + public NotifyUserUseCase(ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread, + LevelUpUseCase levelUpUseCase) { + super(threadExecutor, postExecutionThread); + this.levelUpUseCase = levelUpUseCase; + } + + @Override + protected Observable buildUseCaseObservable(RequestValues r) { + return Observable.from(() -> { + Stats stats = r.user.getStats(); + + if (r.lvl > stats.getLvl()) { + levelUpUseCase.observable(new LevelUpUseCase.RequestValues(r.user, r.lvl, r.context)) + .subscribe(aVoid -> { + r.retrieveUser.call(); + stats.setLvl(r.lvl); + }, throwable -> { + }); + } else { + + Pair pair = getNotificationAndAddStatsToUser(r.user, r.xp, r.hp, r.gold, r.mp); + + showSnackbar(r.context, r.snackbarTargetView, pair.first, pair.second); + } + + return null; + }); + } + + public static Pair getNotificationAndAddStatsToUser(HabitRPGUser user, double xp, double hp, double gold, double mp){ + + StringBuilder message = new StringBuilder(); + Stats stats = user.getStats(); + UiUtils.SnackbarDisplayType displayType = UiUtils.SnackbarDisplayType.NORMAL; + + if (xp > stats.getExp()) { + message.append(" + ").append(round(xp - stats.getExp(), 2)).append(" XP"); + stats.setExp(xp); + } + if (hp != stats.getHp()) { + displayType = UiUtils.SnackbarDisplayType.FAILURE; + message.append(" - ").append(round(stats.getHp() - hp, 2)).append(" HP"); + stats.setHp(hp); + } + if (gold > stats.getGp()) { + message.append(" + ").append(round(gold - stats.getGp(), 2)).append(" GP"); + stats.setGp(gold); + } else if (gold < stats.getGp()) { + displayType = UiUtils.SnackbarDisplayType.FAILURE; + message.append(" - ").append(round(stats.getGp() - gold, 2)).append(" GP"); + stats.setGp(gold); + } + if (mp > stats.getMp() && stats.getLvl() >= MIN_LEVEL_FOR_SKILLS) { + message.append(" + ").append(round(mp - stats.getMp(), 2)).append(" MP"); + stats.setMp(mp); + } + + return new Pair<>(message.toString(), displayType); + } + + public static final class RequestValues implements UseCase.RequestValues { + + private AppCompatActivity context; + private View snackbarTargetView; + private Action0 retrieveUser; + private HabitRPGUser user; + private double xp; + private double hp; + private double gold; + private double mp; + private int lvl; + + public RequestValues(AppCompatActivity context, View snackbarTargetView, Action0 retrieveUser, + HabitRPGUser user, double xp, double hp, double gold, double mp, int lvl) { + this.context = context; + this.snackbarTargetView = snackbarTargetView; + this.retrieveUser = retrieveUser; + this.user = user; + this.xp = xp; + this.hp = hp; + this.gold = gold; + this.mp = mp; + this.lvl = lvl; + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeDetailActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeDetailActivity.java index a4dcd1452..b97641fba 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeDetailActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeDetailActivity.java @@ -12,9 +12,26 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; +import com.habitrpg.android.habitica.events.HabitScoreEvent; +import com.habitrpg.android.habitica.events.TaskRemovedEvent; +import com.habitrpg.android.habitica.events.TaskUpdatedEvent; +import com.habitrpg.android.habitica.events.commands.BuyRewardCommand; +import com.habitrpg.android.habitica.events.commands.ChecklistCheckedCommand; +import com.habitrpg.android.habitica.events.commands.TaskCheckedCommand; +import com.habitrpg.android.habitica.helpers.SoundManager; +import com.habitrpg.android.habitica.interactors.BuyRewardUseCase; +import com.habitrpg.android.habitica.interactors.CheckClassSelectionUseCase; +import com.habitrpg.android.habitica.interactors.ChecklistCheckUseCase; +import com.habitrpg.android.habitica.interactors.DailyCheckUseCase; +import com.habitrpg.android.habitica.interactors.DisplayItemDropUseCase; +import com.habitrpg.android.habitica.interactors.HabitScoreUseCase; +import com.habitrpg.android.habitica.interactors.NotifyUserUseCase; +import com.habitrpg.android.habitica.interactors.TodoCheckUseCase; +import com.habitrpg.android.habitica.ui.helpers.UiUtils; import com.magicmicky.habitrpgwrapper.lib.api.IApiClient; import com.habitrpg.android.habitica.HabiticaApplication; import com.habitrpg.android.habitica.R; @@ -23,6 +40,9 @@ import com.habitrpg.android.habitica.ui.fragments.social.challenges.ChallegeDeta import com.habitrpg.android.habitica.ui.fragments.social.challenges.ChallengeTasksRecyclerViewFragment; import com.habitrpg.android.habitica.ui.helpers.MarkdownParser; import com.magicmicky.habitrpgwrapper.lib.models.Challenge; +import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser; +import com.magicmicky.habitrpgwrapper.lib.models.Stats; +import com.magicmicky.habitrpgwrapper.lib.models.TaskDirectionData; import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task; import com.raizlabs.android.dbflow.sql.builder.Condition; import com.raizlabs.android.dbflow.sql.language.Select; @@ -30,6 +50,9 @@ import com.raizlabs.android.dbflow.sql.language.Select; import net.pherth.android.emoji_library.EmojiParser; import net.pherth.android.emoji_library.EmojiTextView; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; + import java.util.ArrayList; import java.util.Map; @@ -39,6 +62,8 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; +import static com.habitrpg.android.habitica.ui.helpers.UiUtils.showSnackbar; + public class ChallengeDetailActivity extends BaseActivity { public static String CHALLENGE_ID = "CHALLENGE_ID"; @@ -52,6 +77,34 @@ public class ChallengeDetailActivity extends BaseActivity { @Inject public IApiClient apiClient; + @BindView(R.id.floating_menu_wrapper) + FrameLayout floatingMenuWrapper; + + // region UseCases + + @Inject + HabitScoreUseCase habitScoreUseCase; + + @Inject + DailyCheckUseCase dailyCheckUseCase; + + @Inject + TodoCheckUseCase todoCheckUseCase; + + @Inject + BuyRewardUseCase buyRewardUseCase; + + @Inject + ChecklistCheckUseCase checklistCheckUseCase; + + @Inject + DisplayItemDropUseCase displayItemDropUseCase; + + @Inject + NotifyUserUseCase notifyUserUseCase; + + // endregion + private ChallengeViewHolder challengeViewHolder; private Challenge challenge; @@ -88,7 +141,6 @@ public class ChallengeDetailActivity extends BaseActivity { .subscribe(taskList -> { ArrayList resultList = new ArrayList<>(); - ArrayList todos = new ArrayList<>(); ArrayList habits = new ArrayList<>(); ArrayList dailies = new ArrayList<>(); @@ -275,4 +327,86 @@ public class ChallengeDetailActivity extends BaseActivity { public void onBackPressed() { finish(); } + + + + @Subscribe + public void onEvent(TaskCheckedCommand event) { + switch (event.Task.type) { + case Task.TYPE_DAILY: { + dailyCheckUseCase.observable(new DailyCheckUseCase.RequestValues(event.Task, !event.Task.getCompleted())) + .subscribe(res -> { + EventBus.getDefault().post(new TaskUpdatedEvent(event.Task)); + }, error -> { + }); + } + break; + case Task.TYPE_TODO: { + todoCheckUseCase.observable(new TodoCheckUseCase.RequestValues(event.Task, !event.Task.getCompleted())) + .subscribe(res -> { + EventBus.getDefault().post(new TaskUpdatedEvent(event.Task)); + }, error -> { + }); + } + break; + } + } + + @Subscribe + public void onEvent(ChecklistCheckedCommand event) { + checklistCheckUseCase.observable(new ChecklistCheckUseCase.RequestValues(event.task.getId(), event.item.getId())) + .subscribe(res -> { + EventBus.getDefault().post(new TaskUpdatedEvent(event.task)); + }, error -> { + }); + } + + @Subscribe + public void onEvent(HabitScoreEvent event) { + habitScoreUseCase.observable(new HabitScoreUseCase.RequestValues(event.habit, event.Up)) + .subscribe(res -> { + onTaskDataReceived(res, event.habit); + }, error -> { + }); + } + + @Subscribe + public void onEvent(final BuyRewardCommand event) { + final String rewardKey = event.Reward.getId(); + + if (HabiticaApplication.User.getStats().getGp() < event.Reward.getValue()) { + showSnackbar(this, floatingMenuWrapper, getString(R.string.no_gold), UiUtils.SnackbarDisplayType.FAILURE); + return; + } + + + if (event.Reward.specialTag == null || !event.Reward.specialTag.equals("item")) { + + buyRewardUseCase.observable(new BuyRewardUseCase.RequestValues(event.Reward)) + .subscribe(res -> { + onTaskDataReceived(res, event.Reward); + }, error -> {}); + } + + } + + public void onTaskDataReceived(TaskDirectionData data, Task task) { + if (task.type.equals("reward")) { + + showSnackbar(this, floatingMenuWrapper, getString(R.string.notification_purchase, task.getText()), UiUtils.SnackbarDisplayType.NORMAL); + + } else { + + if (HabiticaApplication.User != null) { + notifyUserUseCase.observable(new NotifyUserUseCase.RequestValues(this, floatingMenuWrapper, () -> { + // retrieveUser? forward message to MainActivity ? or mark it to refresh ? + }, + HabiticaApplication.User, data.getExp(), data.getHp(), data.getGp(), data.getMp(), data.getLvl())); + } + + displayItemDropUseCase.observable(new DisplayItemDropUseCase.RequestValues(data, this, floatingMenuWrapper)) + .subscribe(aVoid -> {}, throwable -> {}); + } + } + } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java index d78c87827..f2c71a9f4 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java @@ -2,8 +2,11 @@ package com.habitrpg.android.habitica.ui.activities; import com.facebook.drawee.view.SimpleDraweeView; import com.habitrpg.android.habitica.interactors.BuyRewardUseCase; +import com.habitrpg.android.habitica.interactors.CheckClassSelectionUseCase; import com.habitrpg.android.habitica.interactors.ChecklistCheckUseCase; import com.habitrpg.android.habitica.interactors.DailyCheckUseCase; +import com.habitrpg.android.habitica.interactors.DisplayItemDropUseCase; +import com.habitrpg.android.habitica.interactors.NotifyUserUseCase; import com.habitrpg.android.habitica.interactors.TodoCheckUseCase; import com.magicmicky.habitrpgwrapper.lib.api.IApiClient; import com.habitrpg.android.habitica.HabiticaApplication; @@ -162,6 +165,7 @@ import retrofit2.adapter.rxjava.HttpException; import rx.Observable; import rx.functions.Action1; +import static com.habitrpg.android.habitica.interactors.NotifyUserUseCase.MIN_LEVEL_FOR_SKILLS; import static com.habitrpg.android.habitica.ui.helpers.UiUtils.SnackbarDisplayType; import static com.habitrpg.android.habitica.ui.helpers.UiUtils.showSnackbar; @@ -170,12 +174,12 @@ public class MainActivity extends BaseActivity implements Action1, Ha public static final int SELECT_CLASS_RESULT = 11; public static final int GEM_PURCHASE_REQUEST = 111; - public static final int MIN_LEVEL_FOR_SKILLS = 11; @Inject public IApiClient apiClient; @Inject public SoundManager soundManager; + @Inject public MaintenanceApiService maintenanceService; public HabitRPGUser user; @@ -197,6 +201,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha @BindView(R.id.overlayFrameLayout) FrameLayout overlayFrameLayout; + // region UseCases + @Inject HabitScoreUseCase habitScoreUseCase; @@ -212,6 +218,17 @@ public class MainActivity extends BaseActivity implements Action1, Ha @Inject ChecklistCheckUseCase checklistCheckUseCase; + @Inject + CheckClassSelectionUseCase checkClassSelectionUseCase; + + @Inject + DisplayItemDropUseCase displayItemDropUseCase; + + @Inject + NotifyUserUseCase notifyUserUseCase; + + // endregion + private Drawer drawer; private Drawer filterDrawer; private AccountHeader accountHeader; @@ -244,9 +261,6 @@ public class MainActivity extends BaseActivity implements Action1, Ha } }; - static public Double round(Double value, int n) { - return (Math.round(value * Math.pow(10, n))) / (Math.pow(10, n)); - } PushNotificationManager pushNotificationManager; @@ -312,9 +326,7 @@ public class MainActivity extends BaseActivity implements Action1, Ha //resync, if last sync was more than 10 minutes ago if (this.lastSync == null || (new Date().getTime() - this.lastSync.getTime()) > 180000) { if (this.apiClient != null && this.apiClient.hasAuthenticationKeys()) { - this.apiClient.retrieveUser(true) - .subscribe(new HabitRPGUserCallback(this), throwable -> { - }); + retrieveUser(); this.checkMaintenance(); } } @@ -412,7 +424,7 @@ public class MainActivity extends BaseActivity implements Action1, Ha } } - private void setUserData(boolean fromLocalDb) { + protected void setUserData(boolean fromLocalDb) { if (user != null) { Preferences preferences = user.getPreferences(); @@ -1083,7 +1095,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha buyRewardUseCase.observable(new BuyRewardUseCase.RequestValues(event.Reward)) .subscribe(res -> { onTaskDataReceived(res, event.Reward); - }, error -> {}); + }, error -> { + }); } //Update the users gold @@ -1238,65 +1251,15 @@ public class MainActivity extends BaseActivity implements Action1, Ha } else { if (user != null) { - notifyUser(data.getExp(), data.getHp(), data.getGp(), data.getMp(), data.getLvl()); + notifyUserUseCase.observable(new NotifyUserUseCase.RequestValues(this, floatingMenuWrapper, this::retrieveUser, + user, data.getExp(), data.getHp(), data.getGp(), data.getMp(), data.getLvl())); } - showSnackBarForDataReceived(data); + displayItemDropUseCase.observable(new DisplayItemDropUseCase.RequestValues(data, this, floatingMenuWrapper)) + .subscribe(aVoid -> {}, throwable -> {}); } } - private void showSnackBarForDataReceived(final TaskDirectionData data) { - if (data.get_tmp() != null) { - if (data.get_tmp().getDrop() != null) { - new Handler().postDelayed(() -> { - showSnackbar(MainActivity.this, floatingMenuWrapper, data.get_tmp().getDrop().getDialog(), SnackbarDisplayType.DROP); - soundManager.loadAndPlayAudio(SoundManager.SoundItemDrop); - }, 3000L); - } - } - } - - private void notifyUser(double xp, double hp, double gold, double mp, int lvl) { - StringBuilder message = new StringBuilder(); - SnackbarDisplayType displayType = SnackbarDisplayType.NORMAL; - if (lvl > user.getStats().getLvl()) { - displayLevelUpDialog(lvl); - - this.apiClient.retrieveUser(true) - - .subscribe(new HabitRPGUserCallback(this), throwable -> { - }); - user.getStats().setLvl(lvl); - - showSnackbar(this, floatingMenuWrapper, message.toString(), SnackbarDisplayType.NORMAL); - } else { - com.magicmicky.habitrpgwrapper.lib.models.Stats stats = user.getStats(); - - if (xp > stats.getExp()) { - message.append(" + ").append(round(xp - stats.getExp(), 2)).append(" XP"); - user.getStats().setExp(xp); - } - if (hp != stats.getHp()) { - displayType = SnackbarDisplayType.FAILURE; - message.append(" - ").append(round(stats.getHp() - hp, 2)).append(" HP"); - user.getStats().setHp(hp); - } - if (gold > stats.getGp()) { - message.append(" + ").append(round(gold - stats.getGp(), 2)).append(" GP"); - stats.setGp(gold); - } else if (gold < stats.getGp()) { - displayType = SnackbarDisplayType.FAILURE; - message.append(" - ").append(round(stats.getGp() - gold, 2)).append(" GP"); - stats.setGp(gold); - } - if (mp > stats.getMp() && stats.getLvl() >= MIN_LEVEL_FOR_SKILLS) { - message.append(" + ").append(round(mp - stats.getMp(), 2)).append(" MP"); - stats.setMp(mp); - } - showSnackbar(this, floatingMenuWrapper, message.toString(), displayType); - } - setUserData(true); - } private void displayDeathDialogIfNeeded() { @@ -1335,57 +1298,6 @@ public class MainActivity extends BaseActivity implements Action1, Ha } } - private void displayLevelUpDialog(int level) { - soundManager.loadAndPlayAudio(SoundManager.SoundLevelUp); - - SuppressedModals suppressedModals = user.getPreferences().getSuppressModals(); - if (suppressedModals != null) { - if (suppressedModals.getLevelUp()) { - checkClassSelection(); - return; - } - } - - View customView = getLayoutInflater().inflate(R.layout.dialog_levelup, null); - if (customView != null) { - TextView detailView = (TextView) customView.findViewById(R.id.levelupDetail); - detailView.setText(this.getString(R.string.levelup_detail, level)); - dialogAvatarView = (AvatarView) customView.findViewById(R.id.avatarView); - dialogAvatarView.setUser(user); - } - - final ShareEvent event = new ShareEvent(); - event.sharedMessage = getString(R.string.share_levelup, level) + " https://habitica.com/social/level-up"; - AvatarView avatarView = new AvatarView(this, true, true, true); - avatarView.setUser(user); - avatarView.onAvatarImageReady(avatarImage -> event.shareImage = avatarImage); - - AlertDialog alert = new AlertDialog.Builder(this) - .setTitle(R.string.levelup_header) - .setView(customView) - .setPositiveButton(R.string.levelup_button, (dialog, which) -> { - checkClassSelection(); - }) - .setNeutralButton(R.string.share, (dialog, which) -> { - EventBus.getDefault().post(event); - dialog.dismiss(); - }) - .create(); - if (!this.isFinishing()) { - alert.show(); - } - } - - private void checkClassSelection() { - if (user.getStats().getLvl() > 10 && - !user.getPreferences().getDisableClasses() && - !user.getFlags().getClassSelected()) { - SelectClassEvent event = new SelectClassEvent(); - event.isInitialSelection = true; - event.currentClass = user.getStats().get_class().toString(); - displayClassSelectionActivity(event); - } - } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { @@ -1401,23 +1313,18 @@ public class MainActivity extends BaseActivity implements Action1, Ha return floatingMenuWrapper; } + protected void retrieveUser() { + this.apiClient.retrieveUser(true) + .subscribe(new HabitRPGUserCallback(this), throwable -> { + }); + } + @Subscribe public void displayClassSelectionActivity(SelectClassEvent event) { - Bundle bundle = new Bundle(); - bundle.putString("size", user.getPreferences().getSize()); - bundle.putString("skin", user.getPreferences().getSkin()); - bundle.putString("shirt", user.getPreferences().getShirt()); - bundle.putInt("hairBangs", user.getPreferences().getHair().getBangs()); - bundle.putInt("hairBase", user.getPreferences().getHair().getBase()); - bundle.putString("hairColor", user.getPreferences().getHair().getColor()); - bundle.putInt("hairMustache", user.getPreferences().getHair().getMustache()); - bundle.putInt("hairBeard", user.getPreferences().getHair().getBeard()); - bundle.putBoolean("isInitialSelection", event.isInitialSelection); - bundle.putString("currentClass", event.currentClass); - - Intent intent = new Intent(this, ClassSelectionActivity.class); - intent.putExtras(bundle); - startActivityForResult(intent, SELECT_CLASS_RESULT); + checkClassSelectionUseCase.observable(new CheckClassSelectionUseCase.RequestValues(user, event)) + .subscribe(aVoid -> { + }, throwable -> { + }); } private void displayTutorialStep(TutorialStep step, String text) { @@ -1506,7 +1413,7 @@ public class MainActivity extends BaseActivity implements Action1, Ha case Task.TYPE_TODO: { todoCheckUseCase.observable(new TodoCheckUseCase.RequestValues(event.Task, !event.Task.getCompleted())) .subscribe(res -> { - EventBus.getDefault().post(new TaskUpdatedEvent(event.Task)); + EventBus.getDefault().post(new TaskUpdatedEvent(event.Task)); }, error -> { }); } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.java index abe66276c..dfc1abcaf 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.java @@ -37,6 +37,8 @@ import java.util.List; import butterknife.BindView; import rx.Observable; +import static com.habitrpg.android.habitica.helpers.MathHelper.round; + public class SkillsFragment extends BaseMainFragment { private final int TASK_SELECTION_ACTIVITY = 10; @@ -231,11 +233,6 @@ public class SkillsFragment extends BaseMainFragment { } } - static public Double round(Double value, int n) { - return (Math.round(value * Math.pow(10, n))) / (Math.pow(10, n)); - } - - @Override public String customTitle() { return getString(R.string.sidebar_skills); } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeTasksRecyclerViewFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeTasksRecyclerViewFragment.java index ff32f17d7..157187e39 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeTasksRecyclerViewFragment.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeTasksRecyclerViewFragment.java @@ -205,7 +205,7 @@ public class ChallengeTasksRecyclerViewFragment extends BaseFragment { break; } - viewHolder.setDisabled(true); + //viewHolder.setDisabled(true); return viewHolder; } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/BaseWidgetProvider.java b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/BaseWidgetProvider.java index d0997eca8..9abea0f6a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/BaseWidgetProvider.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/BaseWidgetProvider.java @@ -6,19 +6,21 @@ import android.appwidget.AppWidgetProvider; import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.view.View; +import android.support.v4.util.Pair; import android.widget.RemoteViews; import android.widget.Toast; -import com.habitrpg.android.habitica.R; +import com.habitrpg.android.habitica.interactors.NotifyUserUseCase; +import com.habitrpg.android.habitica.ui.helpers.UiUtils; import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser; import com.magicmicky.habitrpgwrapper.lib.models.Stats; import com.magicmicky.habitrpgwrapper.lib.models.TaskDirectionData; import com.raizlabs.android.dbflow.sql.builder.Condition; import com.raizlabs.android.dbflow.sql.language.Select; -import static com.habitrpg.android.habitica.ui.activities.MainActivity.MIN_LEVEL_FOR_SKILLS; -import static com.habitrpg.android.habitica.ui.activities.MainActivity.round; +import static com.habitrpg.android.habitica.helpers.MathHelper.round; +import static com.habitrpg.android.habitica.interactors.NotifyUserUseCase.MIN_LEVEL_FOR_SKILLS; + public abstract class BaseWidgetProvider extends AppWidgetProvider { @@ -69,31 +71,13 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider { return configureRemoteViews(remoteViews, widgetId, columns, rows); } - protected void showToastForTaskDirection(Context context, TaskDirectionData taskDirectionData, String userID) { + protected void showToastForTaskDirection(Context context, TaskDirectionData data, String userID) { HabitRPGUser user = new Select().from(HabitRPGUser.class).where(Condition.column("id").eq(userID)).querySingle(); - Stats stats = user.getStats(); - StringBuilder message = new StringBuilder(); - if (taskDirectionData.exp > stats.getExp()) { - message.append(" + ").append(round(taskDirectionData.exp - stats.getExp(), 2)).append(" XP"); - user.getStats().setExp(taskDirectionData.exp); - } - if (taskDirectionData.hp < stats.getHp()) { - message.append(" - ").append(round(stats.getHp() - taskDirectionData.hp, 2)).append(" HP"); - user.getStats().setHp(taskDirectionData.hp); - } - if (taskDirectionData.gp > stats.getGp()) { - message.append(" + ").append(round(taskDirectionData.gp - stats.getGp(), 2)).append(" GP"); - user.getStats().setGp(taskDirectionData.gp); - } else if (taskDirectionData.gp < stats.getGp()) { - message.append(" - ").append(round(stats.getGp() - taskDirectionData.gp, 2)).append(" GP"); - stats.setGp(taskDirectionData.gp); - } - if (taskDirectionData.mp > stats.getMp() && stats.getLvl() >= MIN_LEVEL_FOR_SKILLS) { - message.append(" + ").append(round(taskDirectionData.mp - stats.getMp(), 2)).append(" MP"); - user.getStats().setMp(taskDirectionData.mp); - } + + Pair pair = NotifyUserUseCase.getNotificationAndAddStatsToUser(user, data.exp, data.hp, data.getGp(), data.mp); + user.save(); - Toast toast = Toast.makeText(context, message, Toast.LENGTH_LONG); + Toast toast = Toast.makeText(context, pair.first, Toast.LENGTH_LONG); toast.show(); } diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/api/ApiService.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/api/ApiService.java index bc12b19d4..5641255f8 100644 --- a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/api/ApiService.java +++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/api/ApiService.java @@ -100,9 +100,6 @@ public interface ApiService { @GET("tasks/user") Observable> getTasks(); - @GET("tasks/user") - Observable>> getUserTasks(); - @POST("user/unlock") Observable> unlockPath(@Query("path") String path);