diff --git a/Habitica/res/layout/dialog_challenge_filter.xml b/Habitica/res/layout/dialog_challenge_filter.xml
index 7ed2f808c..4c98db44f 100644
--- a/Habitica/res/layout/dialog_challenge_filter.xml
+++ b/Habitica/res/layout/dialog_challenge_filter.xml
@@ -18,41 +18,9 @@
android:layout_marginLeft="@dimen/dialog_marginLeftRight"
android:layout_marginRight="@dimen/dialog_marginLeftRight"
android:layout_marginStart="@dimen/dialog_marginLeftRight"
+ android:layout_marginTop="16dp"
+
android:orientation="vertical">
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="wrap_content"
+ android:gravity="center">
@@ -78,22 +44,23 @@
style="@style/Body1_Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="right"
+ android:gravity="right|center_vertical"
android:text="@string/all"
android:textColor="#6133b4"
- android:textSize="16sp" />
+ android:textSize="16sp"
+ android:padding="0dp" />
-
-
+ android:textSize="16sp"
+ android:padding="0dp"/>
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:text="@string/owned"
+ android:textColor="@color/textColorLight"/>
-
-
-
-
-
+ android:text="@string/not_owned"
+ android:textColor="@color/textColorLight"/>
\ No newline at end of file
diff --git a/Habitica/res/layout/fragment_challengeslist.xml b/Habitica/res/layout/fragment_challengeslist.xml
index a8a5e2b65..c95d0f2b5 100644
--- a/Habitica/res/layout/fragment_challengeslist.xml
+++ b/Habitica/res/layout/fragment_challengeslist.xml
@@ -1,82 +1,29 @@
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
diff --git a/Habitica/res/layout/fragment_refresh_recyclerview.xml b/Habitica/res/layout/fragment_refresh_recyclerview.xml
index 2ac93f84e..89b961273 100644
--- a/Habitica/res/layout/fragment_refresh_recyclerview.xml
+++ b/Habitica/res/layout/fragment_refresh_recyclerview.xml
@@ -2,7 +2,7 @@
diff --git a/Habitica/res/menu/menu_list_challenges.xml b/Habitica/res/menu/menu_list_challenges.xml
index 1b553db6a..d826b3520 100644
--- a/Habitica/res/menu/menu_list_challenges.xml
+++ b/Habitica/res/menu/menu_list_challenges.xml
@@ -7,4 +7,16 @@
android:id="@+id/action_create_challenge"
android:title="@string/create_challenge"/>
+
+
+
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index f1d39dcb1..2470725fb 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -488,101 +488,102 @@
For Subscribing you are receiving these useful benefits:
Subscription Status
- by %s
- Challenge Details
- Leave Challenge
- Are you sure you want to leave the Challenge “%s”?
- Remove tasks
- Do you want to remove the tasks?
- Remove
- Keep
- My Challenges
- Public
- Challenges
- Daily
- Habit
- Reward
- To-Do
- Official
- Participating
- Challenge
- Go to Challenge
- You’re not part of any Challenges right now!
- Join a Challenge to add a curated set of tasks to your list, then compete against other Habiticans to win achievements and even gems!
- Tap the “Public” tab to find the user-created Challenges that are the best fit for you!
- Add Reminder
- Warning
- Open Settings
- It seems like you have the Developer option \“Don\'t keep Activities\” active. Currently this option causes issues with the habitica app, so we suggest disabling it.
- Inbox
- Frequently Asked Questions
- Special
- Because you subscribe to Habitica, you can purchase a number of Gems each month using Gold.
- %d left
- Gem
- Mystery Item
- Each month, subscribers will receive a mystery item. This is usually released about one week before the end of the month.
- Open
- You open the box and find %s!
- You earned a %1$s as a reward for your devotion to improving your life.
- Your next prize unlocks at %1$d Check-Ins
- pending approval
- Filters
- Done
- Group tasks can not be edited.
- Can\'t edit this task
- Groups
- All
- None
- Owned
- Not owned
- New\nGame
- Login with Facebook
- Login with Google
- Back
- Oh, you must be new here. I’m Justin, I’ll be your guide in Habitica.\n\nTo start, you’ll need to create an avatar.
- Randomize
- Extras
- Skin Color
- Hair Color
- Bangs
- Ponytail
- Glasses
- Wheelchair
- Weak
- Strong
- Grey
- Dated
- Completed
- Other
- Clear
- You don\'t have any Habits
- Habits are tasks that don\'t have a rigid schedule. You can check them off many times a day, or not at all.
- You don\'t have any Dailies
- Dailies are tasks that repeat on a regular basis. Choose the schedule that works for you!
- You don\'t have any To-Dos
- To-Dos are tasks that only need to be completed once. Add checklists to your To-Dos to increase their value.
- You don\'t have any Rewards
- Reset Justins Walkthrough
- Please read our Community Guidelines before posting
- Maintenance
- Reload Content
- Set Dailies default to ‘due’ tab
- With this option set, the Dailies tasks will default to ‘due’ instead of ‘all’
- Your device does not have any of the supported payment methods. Please use the habitica website if you want to purchase gems.
- Your device does not have any of the supported payment methods. Please use the habitica website if you want to purchase a subscription.
- Save
- Location
- Gem reward
- Tasks
- Create challenge
- Edit Challenge
- You need at least 1 gem to create a challenge in Tavern.
- You don\'t have enough gems to create a challenge.
- Identify your challenge with a tag ..
- You need a tag to create this Challenge.
- You need to add at least one task to create this Challenge.
- You need a title to create this Challenge.
- Description (optional)
- New challenge title
+ by %s
+ Challenge Details
+ Leave Challenge
+ Are you sure you want to leave the Challenge “%s”?
+ Remove tasks
+ Do you want to remove the tasks?
+ Remove
+ Keep
+ My Challenges
+ Public
+ Challenges
+ Daily
+ Habit
+ Reward
+ To-Do
+ Official
+ Participating
+ Challenge
+ Go to Challenge
+ You’re not part of any Challenges right now!
+ Join a Challenge to add a curated set of tasks to your list, then compete against other Habiticans to win achievements and even gems!
+ Tap the “Public” tab to find the user-created Challenges that are the best fit for you!
+ Add Reminder
+ Warning
+ Open Settings
+ It seems like you have the Developer option \“Don\'t keep Activities\” active. Currently this option causes issues with the habitica app, so we suggest disabling it.
+ Inbox
+ Frequently Asked Questions
+ Special
+ Because you subscribe to Habitica, you can purchase a number of Gems each month using Gold.
+ %d left
+ Gem
+ Mystery Item
+ Each month, subscribers will receive a mystery item. This is usually released about one week before the end of the month.
+ Open
+ You open the box and find %s!
+ You earned a %1$s as a reward for your devotion to improving your life.
+ Your next prize unlocks at %1$d Check-Ins
+ pending approval
+ Filters
+ Done
+ Group tasks can not be edited.
+ Can\'t edit this task
+ Groups
+ All
+ None
+ Owned
+ Not owned
+ New\nGame
+ Login with Facebook
+ Login with Google
+ Back
+ Oh, you must be new here. I’m Justin, I’ll be your guide in Habitica.\n\nTo start, you’ll need to create an avatar.
+ Randomize
+ Extras
+ Skin Color
+ Hair Color
+ Bangs
+ Ponytail
+ Glasses
+ Wheelchair
+ Weak
+ Strong
+ Grey
+ Dated
+ Completed
+ Other
+ Clear
+ You don\'t have any Habits
+ Habits are tasks that don\'t have a rigid schedule. You can check them off many times a day, or not at all.
+ You don\'t have any Dailies
+ Dailies are tasks that repeat on a regular basis. Choose the schedule that works for you!
+ You don\'t have any To-Dos
+ To-Dos are tasks that only need to be completed once. Add checklists to your To-Dos to increase their value.
+ You don\'t have any Rewards
+ Reset Justins Walkthrough
+ Please read our Community Guidelines before posting
+ Maintenance
+ Reload Content
+ Set Dailies default to ‘due’ tab
+ With this option set, the Dailies tasks will default to ‘due’ instead of ‘all’
+ Your device does not have any of the supported payment methods. Please use the habitica website if you want to purchase gems.
+ Your device does not have any of the supported payment methods. Please use the habitica website if you want to purchase a subscription.
+ Save
+ Location
+ Gem reward
+ Tasks
+ Create challenge
+ Edit Challenge
+ You need at least 1 gem to create a challenge in Tavern.
+ You don\'t have enough gems to create a challenge.
+ Identify your challenge with a tag ..
+ You need a tag to create this Challenge.
+ You need to add at least one task to create this Challenge.
+ You need a title to create this Challenge.
+ Description (optional)
+ New challenge title
+ Ownership
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java b/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java
index 911276a23..1eef54975 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java
@@ -29,7 +29,6 @@ import com.habitrpg.android.habitica.models.tasks.TaskList;
import com.habitrpg.android.habitica.models.user.Items;
import com.habitrpg.android.habitica.models.user.User;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -109,7 +108,7 @@ public interface ApiService {
Observable> postTaskDirection(@Path("id") String id, @Path("direction") String direction);
@POST("tasks/{id}/move/to/{position}")
- Observable>> postTaskNewPosition(@Path("id") String id, @Path("position") String position);
+ Observable>> postTaskNewPosition(@Path("id") String id, @Path("position") String position);
@POST("tasks/{taskId}/checklist/{itemId}/score")
Observable> scoreChecklistItem(@Path("taskId") String taskId, @Path("itemId") String itemId);
@@ -273,7 +272,7 @@ public interface ApiService {
/* challenges api */
@GET("challenges/user")
- Observable>> getUserChallenges();
+ Observable>> getUserChallenges();
@GET("tasks/challenge/{challengeId}")
Observable> getChallengeTasks(@Path("challengeId") String challengeId);
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java b/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
index 7914b6b81..9ccf50bc2 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
@@ -71,6 +71,7 @@ import com.habitrpg.android.habitica.ui.fragments.social.InboxFragment;
import com.habitrpg.android.habitica.ui.fragments.social.InboxMessageListFragment;
import com.habitrpg.android.habitica.ui.fragments.social.PublicGuildsFragment;
import com.habitrpg.android.habitica.ui.fragments.social.TavernFragment;
+import com.habitrpg.android.habitica.ui.fragments.social.challenges.ChallengeDetailDialogHolder;
import com.habitrpg.android.habitica.ui.fragments.social.challenges.ChallengeListFragment;
import com.habitrpg.android.habitica.ui.fragments.social.challenges.ChallengeTasksRecyclerViewFragment;
import com.habitrpg.android.habitica.ui.fragments.social.challenges.ChallengesOverviewFragment;
@@ -262,4 +263,6 @@ public interface AppComponent {
void inject(NotificationPublisher notificationPublisher);
void inject(CreateChallengeActivity createChallengeActivity);
+
+ void inject(ChallengeDetailDialogHolder challengeDetailDialogHolder);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ChallengeRepository.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ChallengeRepository.java
index e46148601..8170a4f73 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ChallengeRepository.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ChallengeRepository.java
@@ -1,12 +1,15 @@
package com.habitrpg.android.habitica.data;
+import com.habitrpg.android.habitica.models.LeaveChallengeBody;
import com.habitrpg.android.habitica.models.social.Challenge;
import com.habitrpg.android.habitica.models.social.Group;
import com.habitrpg.android.habitica.models.tasks.Task;
import com.habitrpg.android.habitica.models.tasks.TaskList;
+import com.habitrpg.android.habitica.models.user.User;
import java.util.List;
+import io.realm.RealmResults;
import rx.Observable;
public interface ChallengeRepository extends BaseRepository {
@@ -17,18 +20,23 @@ public interface ChallengeRepository extends BaseRepository {
/**
*
- * @param challenge
+ * @param challenge the challenge that will be updated
* @param fullTaskList lists all tasks of the current challenge, to create the taskOrders
* @param addedTaskList only the tasks to be added online
* @param updatedTaskList only the updated ones
* @param removedTaskList tasks that has be to be removed
- * @return
+ * @return Observable with the updated challenge
*/
Observable updateChallenge(Challenge challenge, List fullTaskList,
List addedTaskList, List updatedTaskList, List removedTaskList);
Observable deleteChallenge(String challengeId);
- void setUsersGroups(List groups);
+ Observable> getChallenges();
+ Observable> getUserChallenges(String userId);
- Observable> getLocalGroups();
+ Observable> retrieveChallenges(User user);
+
+ Observable leaveChallenge(Challenge challenge, LeaveChallengeBody leaveChallengeBody);
+
+ Observable joinChallenge(Challenge challenge);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.java
index d680c90ca..68bd8ee81 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.java
@@ -38,7 +38,7 @@ public interface SocialRepository extends BaseRepository {
Observable updateGroup(Group group);
Observable> retrieveGroups(String type);
- Observable> getGroups(String type);
+ Observable> getGroups(String type);
Observable postPrivateMessage(HashMap messageObject);
Observable postPrivateMessage(String recipientId, String message);
@@ -52,10 +52,5 @@ public interface SocialRepository extends BaseRepository {
Observable getMember(String userId);
- Observable getChallenge(String challengeId);
-
- Observable> getChallenges();
- Observable> getUserChallenges(String id);
-
Observable markPrivateMessagesRead(User user);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java
index ff883d593..9e1633eff 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java
@@ -66,6 +66,7 @@ import com.habitrpg.android.habitica.models.tasks.Task;
import com.habitrpg.android.habitica.models.tasks.TaskList;
import com.habitrpg.android.habitica.utils.BooleanAsIntAdapter;
import com.habitrpg.android.habitica.utils.ChallengeDeserializer;
+import com.habitrpg.android.habitica.utils.ChallengeListDeserializer;
import com.habitrpg.android.habitica.utils.ChatMessageDeserializer;
import com.habitrpg.android.habitica.utils.ChatMessageListDeserializer;
import com.habitrpg.android.habitica.utils.ChecklistItemSerializer;
@@ -208,38 +209,23 @@ public class ApiClientImpl implements Action1, ApiClient {
}
public static GsonConverterFactory createGsonFactory() {
- Type taskTagClassListType = new TypeToken>() {
- }.getType();
- Type skillListType = new TypeToken>() {
- }.getType();
- Type customizationListType = new TypeToken>() {
- }.getType();
- Type tutorialStepListType = new TypeToken>() {
- }.getType();
- Type faqArticleListType = new TypeToken>() {
- }.getType();
- Type itemDataListType = new TypeToken>() {
- }.getType();
- Type eggListType = new TypeToken>() {
- }.getType();
- Type foodListType = new TypeToken>() {
- }.getType();
- Type hatchingPotionListType = new TypeToken>() {
- }.getType();
- Type questContentListType = new TypeToken>() {
- }.getType();
- Type petMapType = new TypeToken>() {
- }.getType();
- Type mountMapType = new TypeToken>() {
- }.getType();
- Type petListType = new TypeToken>() {
- }.getType();
- Type mountListType = new TypeToken>() {
- }.getType();
- Type questCollectListType = new TypeToken>() {
- }.getType();
- Type chatMessageListType = new TypeToken>() {
- }.getType();
+ Type taskTagClassListType = new TypeToken>() {}.getType();
+ Type skillListType = new TypeToken>() {}.getType();
+ Type customizationListType = new TypeToken>() {}.getType();
+ Type tutorialStepListType = new TypeToken>() {}.getType();
+ Type faqArticleListType = new TypeToken>() {}.getType();
+ Type itemDataListType = new TypeToken>() {}.getType();
+ Type eggListType = new TypeToken>() {}.getType();
+ Type foodListType = new TypeToken>() {}.getType();
+ Type hatchingPotionListType = new TypeToken>() {}.getType();
+ Type questContentListType = new TypeToken>() {}.getType();
+ Type petMapType = new TypeToken>() {}.getType();
+ Type mountMapType = new TypeToken>() {}.getType();
+ Type petListType = new TypeToken>() {}.getType();
+ Type mountListType = new TypeToken>() {}.getType();
+ Type questCollectListType = new TypeToken>() {}.getType();
+ Type chatMessageListType = new TypeToken>() {}.getType();
+ Type challengeListType = new TypeToken>() {}.getType();
//Exclusion strategy needed for DBFlow https://github.com/Raizlabs/DBFlow/issues/121
Gson gson = new GsonBuilder()
@@ -274,6 +260,7 @@ public class ApiClientImpl implements Action1, ApiClient {
.registerTypeAdapter(User.class, new UserDeserializer())
.registerTypeAdapter(questCollectListType, new QuestCollectDeserializer())
.registerTypeAdapter(chatMessageListType, new ChatMessageListDeserializer())
+ .registerTypeAdapter(challengeListType, new ChallengeListDeserializer())
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.create();
return GsonConverterFactory.create(gson);
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ChallengeRepositoryImpl.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ChallengeRepositoryImpl.java
index 83d364c03..7ee806378 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ChallengeRepositoryImpl.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ChallengeRepositoryImpl.java
@@ -4,16 +4,18 @@ import com.github.underscore.$;
import com.habitrpg.android.habitica.data.ApiClient;
import com.habitrpg.android.habitica.data.ChallengeRepository;
import com.habitrpg.android.habitica.data.local.ChallengeLocalRepository;
+import com.habitrpg.android.habitica.models.LeaveChallengeBody;
import com.habitrpg.android.habitica.models.social.Challenge;
-import com.habitrpg.android.habitica.models.social.Group;
import com.habitrpg.android.habitica.models.tasks.Task;
import com.habitrpg.android.habitica.models.tasks.TaskList;
import com.habitrpg.android.habitica.models.tasks.TasksOrder;
+import com.habitrpg.android.habitica.models.user.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import io.realm.RealmResults;
import rx.Observable;
import rx.schedulers.Schedulers;
@@ -110,12 +112,30 @@ public class ChallengeRepositoryImpl extends BaseRepositoryImpl groups) {
- localRepository.setUsersGroups(groups);
+ public Observable> getChallenges() {
+ return localRepository.getChallenges();
}
@Override
- public Observable> getLocalGroups() {
- return localRepository.getGroups();
+ public Observable> getUserChallenges(String userId) {
+ return localRepository.getUserChallenges(userId);
+ }
+
+ @Override
+ public Observable> retrieveChallenges(User user) {
+ return apiClient.getUserChallenges()
+ .doOnNext(challenges -> localRepository.saveChallenges(user, challenges));
+ }
+
+ @Override
+ public Observable leaveChallenge(Challenge challenge, LeaveChallengeBody leaveChallengeBody) {
+ return apiClient.leaveChallenge(challenge.id, leaveChallengeBody)
+ .doOnNext(aVoid -> localRepository.setParticipating(challenge, false));
+ }
+
+ @Override
+ public Observable joinChallenge(Challenge challenge) {
+ return apiClient.joinChallenge(challenge.id)
+ .doOnNext(aVoid -> localRepository.setParticipating(challenge, true));
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.java
index b1bd0b241..95b3120dc 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.java
@@ -106,8 +106,8 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl> getGroups(String type) {
- return retrieveGroups(type);
+ public Observable> getGroups(String type) {
+ return localRepository.getGroups(type);
}
@Override
@@ -143,21 +143,6 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl getChallenge(String challengeId) {
- return localRepository.getChallenge(challengeId);
- }
-
- @Override
- public Observable> getChallenges() {
- return localRepository.getChallenges();
- }
-
- @Override
- public Observable> getUserChallenges(String userId) {
- return localRepository.getUserChallenges(userId);
- }
-
@Override
public Observable markPrivateMessagesRead(User user) {
return apiClient.markPrivateMessagesRead()
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/ChallengeLocalRepository.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/ChallengeLocalRepository.java
index 42c3e530f..edf882a58 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/ChallengeLocalRepository.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/ChallengeLocalRepository.java
@@ -4,16 +4,22 @@ package com.habitrpg.android.habitica.data.local;
import com.habitrpg.android.habitica.models.social.Challenge;
import com.habitrpg.android.habitica.models.social.Group;
import com.habitrpg.android.habitica.models.tasks.Task;
+import com.habitrpg.android.habitica.models.user.User;
import java.util.List;
+import io.realm.RealmResults;
import rx.Observable;
public interface ChallengeLocalRepository extends BaseLocalRepository {
Observable getChallenge(String id);
Observable> getTasks(Challenge challenge);
- void setUsersGroups(List group);
+ Observable> getChallenges();
- Observable> getGroups();
+ Observable> getUserChallenges(String userId);
+
+ void saveChallenges(User user, List challenges);
+
+ void setParticipating(Challenge challenge, boolean isParticipating);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/SocialLocalRepository.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/SocialLocalRepository.java
index adce34aec..6c2316f62 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/SocialLocalRepository.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/SocialLocalRepository.java
@@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.data.local;
import com.habitrpg.android.habitica.models.social.Challenge;
import com.habitrpg.android.habitica.models.social.ChatMessage;
+import com.habitrpg.android.habitica.models.social.Group;
import java.util.List;
@@ -9,9 +10,5 @@ import io.realm.RealmResults;
import rx.Observable;
public interface SocialLocalRepository extends BaseLocalRepository {
- Observable getChallenge(String challengeId);
-
- Observable> getChallenges();
-
- Observable> getUserChallenges(String userId);
+ Observable> getGroups(String type);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmChallengeLocalRepository.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmChallengeLocalRepository.java
index 8ad2244ca..5858e9d7e 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmChallengeLocalRepository.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmChallengeLocalRepository.java
@@ -4,10 +4,13 @@ import com.habitrpg.android.habitica.data.local.ChallengeLocalRepository;
import com.habitrpg.android.habitica.models.social.Challenge;
import com.habitrpg.android.habitica.models.social.Group;
import com.habitrpg.android.habitica.models.tasks.Task;
+import com.habitrpg.android.habitica.models.user.User;
import java.util.List;
import io.realm.Realm;
+import io.realm.RealmResults;
+import io.realm.Sort;
import rx.Observable;
public class RealmChallengeLocalRepository extends RealmBaseLocalRepository implements ChallengeLocalRepository {
@@ -32,12 +35,31 @@ public class RealmChallengeLocalRepository extends RealmBaseLocalRepository impl
}
@Override
- public void setUsersGroups(List groups) {
-
+ public Observable> getChallenges() {
+ return realm.where(Challenge.class)
+ .isNotNull("name")
+ .findAllSortedAsync("memberCount", Sort.DESCENDING)
+ .asObservable()
+ .filter(RealmResults::isLoaded);
}
@Override
- public Observable> getGroups() {
- return null;
+ public Observable> getUserChallenges(String userId) {
+ return realm.where(Challenge.class)
+ .isNotNull("name")
+ .equalTo("isParticipating", true)
+ .findAllSortedAsync("memberCount", Sort.DESCENDING)
+ .asObservable()
+ .filter(RealmResults::isLoaded);
+ }
+
+ @Override
+ public void saveChallenges(User user, List challenges) {
+ realm.executeTransactionAsync(realm1 -> realm1.copyToRealmOrUpdate(challenges));
+ }
+
+ @Override
+ public void setParticipating(Challenge challenge, boolean isParticipating) {
+ realm.executeTransaction(realm1 -> challenge.isParticipating = isParticipating);
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.java
index 22941907f..8c3193818 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.java
@@ -1,8 +1,7 @@
package com.habitrpg.android.habitica.data.local.implementation;
import com.habitrpg.android.habitica.data.local.SocialLocalRepository;
-import com.habitrpg.android.habitica.models.social.Challenge;
-import com.habitrpg.android.habitica.models.social.ChatMessage;
+import com.habitrpg.android.habitica.models.social.Group;
import io.realm.Realm;
import io.realm.RealmResults;
@@ -16,30 +15,10 @@ public class RealmSocialLocalRepository extends RealmBaseLocalRepository impleme
}
@Override
- public Observable getChallenge(String challengeId) {
- return realm.where(Challenge.class)
- .equalTo("id", challengeId)
- .findFirstAsync()
- .asObservable()
- .filter(realmObject -> realmObject.isLoaded())
- .cast(Challenge.class);
- }
-
- @Override
- public Observable> getChallenges() {
- return realm.where(Challenge.class)
- .isNotNull("name")
- .findAll()
- .asObservable()
- .filter(RealmResults::isLoaded);
- }
-
- @Override
- public Observable> getUserChallenges(String userId) {
- return realm.where(Challenge.class)
- .isNotNull("name")
- .equalTo("userId", userId)
- .findAll()
+ public Observable> getGroups(String type) {
+ return realm.where(Group.class)
+ .equalTo("type", type)
+ .findAllAsync()
.asObservable()
.filter(RealmResults::isLoaded);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/Challenge.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/Challenge.java
index b56e08f8a..ca49155d0 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/Challenge.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/Challenge.java
@@ -29,8 +29,6 @@ public class Challenge extends RealmObject {
public int prize;
public boolean official;
public int memberCount;
- @SerializedName("user_id")
- public String userId;
public String todoList;
public String habitList;
public String dailyList;
@@ -41,6 +39,7 @@ public class Challenge extends RealmObject {
public User leader;
@Ignore
public TasksOrder tasksOrder;
+ public boolean isParticipating;
public HashMap getTasksOrder() {
HashMap map = new HashMap();
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.java
index 999587cc5..0f40adc8c 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.java
@@ -23,8 +23,6 @@ import io.realm.annotations.PrimaryKey;
public class User extends RealmObject {
- @Ignore
- List challengeList;
@Ignore
public TaskList tasks;
@@ -54,21 +52,7 @@ public class User extends RealmObject {
@Ignore
private TasksOrder tasksOrder;
- @Ignore
- private List challenges;
-
-
- public List getChallengeList() {
- return challengeList;
- }
-
- public void setChallengeList(List challenges) {
- this.challengeList = challenges;
- }
-
- public void resetChallengeList() {
- challengeList = null;
- }
+ private RealmList challenges;
public Preferences getPreferences() {
return preferences;
@@ -248,14 +232,6 @@ public class User extends RealmObject {
this.pushDevices = pushDevices;
}
- public List getChallenges() {
- return challenges;
- }
-
- public void setChallenges(List challenges) {
- this.challenges = challenges;
- }
-
public List getAvatarLayerNames() {
List layerNames = new ArrayList();
@@ -467,4 +443,12 @@ public class User extends RealmObject {
public void setTags(RealmList tags) {
this.tags = tags;
}
+
+ public RealmList getChallenges() {
+ return challenges;
+ }
+
+ public void setChallenges(RealmList challenges) {
+ this.challenges = challenges;
+ }
}
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 b464c4e78..865e39c6a 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
@@ -20,8 +20,7 @@ import android.widget.TextView;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.components.AppComponent;
-import com.habitrpg.android.habitica.data.ApiClient;
-import com.habitrpg.android.habitica.data.SocialRepository;
+import com.habitrpg.android.habitica.data.ChallengeRepository;
import com.habitrpg.android.habitica.data.UserRepository;
import com.habitrpg.android.habitica.events.HabitScoreEvent;
import com.habitrpg.android.habitica.events.TaskUpdatedEvent;
@@ -76,9 +75,7 @@ public class ChallengeDetailActivity extends BaseActivity {
Toolbar toolbar;
@Inject
- public ApiClient apiClient;
- @Inject
- SocialRepository socialRepository;
+ ChallengeRepository challengeRepository;
@Inject
@Named(AppModule.NAMED_USER_ID)
String userId;
@@ -154,8 +151,7 @@ public class ChallengeDetailActivity extends BaseActivity {
userRepository.getUser(userId).first().subscribe(user -> ChallengeDetailActivity.this.user = user, ReactiveErrorHandler.handleEmptyError());
if (challengeId != null) {
-
- apiClient.getChallengeTasks(challengeId)
+ challengeRepository.getChallengeTasks(challengeId)
.subscribe(taskList -> {
ArrayList resultList = new ArrayList<>();
@@ -243,7 +239,7 @@ public class ChallengeDetailActivity extends BaseActivity {
}
if (challengeId != null) {
- socialRepository.getChallenge(challengeId).subscribe(challenge -> {
+ challengeRepository.getChallenge(challengeId).subscribe(challenge -> {
ChallengeDetailActivity.this.challenge = challenge;
ChallengeViewHolder challengeViewHolder = new ChallengeViewHolder(findViewById(R.id.challenge_header));
challengeViewHolder.bind(challenge);
@@ -253,13 +249,13 @@ public class ChallengeDetailActivity extends BaseActivity {
@Override
protected void onDestroy() {
- socialRepository.close();
+ challengeRepository.close();
userRepository.close();
super.onDestroy();
}
protected void injectActivity(AppComponent component) {
- openChallengeEditActivity();
+ component.inject(this);
}
@Override
@@ -292,15 +288,8 @@ public class ChallengeDetailActivity extends BaseActivity {
.setPositiveButton(this.getString(R.string.yes), (dialog, which) -> {
dialog.dismiss();
- showRemoveTasksDialog(keepTasks -> this.apiClient.leaveChallenge(challenge.id, new LeaveChallengeBody(keepTasks))
- .subscribe(aVoid -> {
- challenge.userId = null;
-
- user.resetChallengeList();
- finish();
-
- }, throwable -> {
- }));
+ showRemoveTasksDialog(keepTasks -> this.challengeRepository.leaveChallenge(challenge, new LeaveChallengeBody(keepTasks))
+ .subscribe(aVoid -> finish(), throwable -> {}));
})
.setNegativeButton(this.getString(R.string.no), (dialog, which) -> dialog.dismiss()).show();
}
@@ -375,12 +364,9 @@ public class ChallengeDetailActivity extends BaseActivity {
@OnClick(R.id.btn_show_more)
void onShowMore() {
-
- ChallengeDetailDialogHolder.showDialog(ChallengeDetailActivity.this, ChallengeDetailActivity.this.apiClient,
- user, challenge,
- challenge1 -> {
-
- },
+ ChallengeDetailDialogHolder.showDialog(ChallengeDetailActivity.this,
+ ChallengeDetailActivity.this.challengeRepository,
+ challenge,
challenge1 -> ChallengeDetailActivity.this.onBackPressed());
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/CreateChallengeActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/CreateChallengeActivity.java
index 33502e7e8..a36743f91 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/CreateChallengeActivity.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/CreateChallengeActivity.java
@@ -6,6 +6,7 @@ import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout;
@@ -33,12 +34,16 @@ import com.habitrpg.android.habitica.HabiticaApplication;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.components.AppComponent;
import com.habitrpg.android.habitica.data.ChallengeRepository;
+import com.habitrpg.android.habitica.data.SocialRepository;
+import com.habitrpg.android.habitica.data.UserRepository;
import com.habitrpg.android.habitica.events.TaskSaveEvent;
import com.habitrpg.android.habitica.events.TaskTappedEvent;
+import com.habitrpg.android.habitica.helpers.ReactiveErrorHandler;
import com.habitrpg.android.habitica.models.social.Challenge;
import com.habitrpg.android.habitica.models.social.Group;
import com.habitrpg.android.habitica.models.tasks.Task;
import com.habitrpg.android.habitica.models.user.User;
+import com.habitrpg.android.habitica.modules.AppModule;
import com.habitrpg.android.habitica.ui.adapter.social.challenges.ChallengeTasksRecyclerViewAdapter;
import org.greenrobot.eventbus.EventBus;
@@ -47,9 +52,11 @@ import org.greenrobot.eventbus.Subscribe;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Objects;
import java.util.UUID;
import javax.inject.Inject;
+import javax.inject.Named;
import butterknife.BindView;
import butterknife.OnClick;
@@ -100,6 +107,13 @@ public class CreateChallengeActivity extends BaseActivity {
@Inject
ChallengeRepository challengeRepository;
+ @Inject
+ SocialRepository socialRepository;
+ @Inject
+ UserRepository userRepository;
+ @Inject
+ @Named(AppModule.NAMED_USER_ID)
+ String userId;
private ChallengeTasksRecyclerViewAdapter challengeTasks;
@@ -116,8 +130,15 @@ public class CreateChallengeActivity extends BaseActivity {
Task addDaily;
Task addTodo;
Task addReward;
+ @Nullable
private User user;
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
+ super.onCreate(savedInstanceState, persistentState);
+ userRepository.getUser(userId).subscribe(user1 -> this.user = user1, ReactiveErrorHandler.handleEmptyError());
+ }
+
@Override
protected int getLayoutResId() {
return R.layout.activity_create_challenge;
@@ -234,6 +255,8 @@ public class CreateChallengeActivity extends BaseActivity {
@Override
public void onDestroy() {
+ socialRepository.close();
+ challengeRepository.close();
EventBus.getDefault().unregister(this);
super.onDestroy();
}
@@ -288,7 +311,10 @@ public class CreateChallengeActivity extends BaseActivity {
// 0 is Tavern
int selectedLocation = challengeLocationSpinner.getSelectedItemPosition();
- double gemCount = user.getGemCount();
+ double gemCount = 0;
+ if (user != null) {
+ gemCount = user.getGemCount();
+ }
if (selectedLocation == 0 && currentVal == 0) {
createChallengeGemError.setVisibility(View.VISIBLE);
@@ -324,7 +350,7 @@ public class CreateChallengeActivity extends BaseActivity {
locationAdapter = new GroupArrayAdapter(this);
locationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- challengeRepository.getLocalGroups().subscribe(groups -> {
+ socialRepository.getGroups("guild").subscribe(groups -> {
Group tavern = new Group();
tavern.id = "00000000-0000-4000-A000-000000000000";
tavern.name = getString(R.string.sidebar_tavern);
@@ -332,7 +358,7 @@ public class CreateChallengeActivity extends BaseActivity {
locationAdapter.add(tavern);
groups.forEach(group -> locationAdapter.add(group));
- }, Throwable::printStackTrace);
+ }, ReactiveErrorHandler.handleEmptyError());
challengeLocationSpinner.setAdapter(locationAdapter);
challengeLocationSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@@ -410,12 +436,12 @@ public class CreateChallengeActivity extends BaseActivity {
createChallengeTitle.setText(challenge.name);
createChallengeDescription.setText(challenge.description);
createChallengeTag.setText(challenge.shortName);
- createChallengePrize.setText(challenge.prize + "");
+ createChallengePrize.setText(String.valueOf(challenge.prize));
for (int i = 0; i < locationAdapter.getCount(); i++) {
Group group = locationAdapter.getItem(i);
- if (group.id == challenge.groupId) {
+ if (group != null && challenge.groupId.equals(group.id)) {
challengeLocationSpinner.setSelection(i);
break;
}
@@ -542,7 +568,7 @@ public class CreateChallengeActivity extends BaseActivity {
}
private class GroupArrayAdapter extends ArrayAdapter {
- public GroupArrayAdapter(@NonNull Context context) {
+ GroupArrayAdapter(@NonNull Context context) {
super(context, android.R.layout.simple_spinner_item);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChallengesListViewAdapter.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChallengesListViewAdapter.java
index c6e1b193b..79c93b66e 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChallengesListViewAdapter.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChallengesListViewAdapter.java
@@ -10,60 +10,28 @@ import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
-import com.github.underscore.$;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.events.commands.ShowChallengeDetailActivityCommand;
import com.habitrpg.android.habitica.events.commands.ShowChallengeDetailDialogCommand;
import com.habitrpg.android.habitica.models.social.Challenge;
-import com.habitrpg.android.habitica.models.user.User;
-import com.habitrpg.android.habitica.ui.fragments.social.challenges.ChallengeFilterOptions;
import net.pherth.android.emoji_library.EmojiParser;
import net.pherth.android.emoji_library.EmojiTextView;
import org.greenrobot.eventbus.EventBus;
-import java.util.ArrayList;
-import java.util.List;
-
import butterknife.BindView;
import butterknife.ButterKnife;
+import io.realm.OrderedRealmCollection;
+import io.realm.RealmRecyclerViewAdapter;
-public class ChallengesListViewAdapter extends RecyclerView.Adapter {
- private List challenges = new ArrayList<>();
- private List challengesSource = new ArrayList<>();
+public class ChallengesListViewAdapter extends RealmRecyclerViewAdapter {
private boolean viewUserChallengesOnly;
- @Nullable
- private User user;
- public ChallengesListViewAdapter(boolean viewUserChallengesOnly, @Nullable User user) {
+ public ChallengesListViewAdapter(@Nullable OrderedRealmCollection data, boolean autoUpdate, boolean viewUserChallengesOnly) {
+ super(data, autoUpdate);
this.viewUserChallengesOnly = viewUserChallengesOnly;
- this.user = user;
- }
-
- public void setChallenges(List challenges) {
- this.challengesSource = challenges;
- this.challenges = new ArrayList<>(challengesSource);
- this.notifyDataSetChanged();
- }
-
- public void setFilterByGroups(ChallengeFilterOptions filterOptions){
- this.challenges = $.filter(challengesSource, arg -> {
- boolean showChallenge = $.find(filterOptions.showByGroups, g -> g.id.contains(arg.groupId)).isPresent();
-
- boolean showByOwnership = true;
- if(filterOptions.showOwned == filterOptions.notOwned && this.user != null){
- if (filterOptions.showOwned) {
- showByOwnership = arg.leaderId.equals(this.user.getId());
- } else {
- showByOwnership = !arg.leaderId.equals(this.user.getId());
- }
- }
-
- return showChallenge && showByOwnership;
- });
- this.notifyDataSetChanged();
}
@Override
@@ -76,36 +44,7 @@ public class ChallengesListViewAdapter extends RecyclerView.Adapter {
- });
+ }, throwable -> {});
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailDialogHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailDialogHolder.java
index f925a44eb..74ad1c4b4 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailDialogHolder.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailDialogHolder.java
@@ -11,8 +11,10 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.habitrpg.android.habitica.HabiticaApplication;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.data.ApiClient;
+import com.habitrpg.android.habitica.data.ChallengeRepository;
import com.habitrpg.android.habitica.events.commands.OpenFullProfileCommand;
import com.habitrpg.android.habitica.models.LeaveChallengeBody;
import com.habitrpg.android.habitica.models.social.Challenge;
@@ -30,6 +32,8 @@ import org.greenrobot.eventbus.EventBus;
import java.util.ArrayList;
import java.util.Map;
+import javax.inject.Inject;
+
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
@@ -37,6 +41,7 @@ import rx.functions.Action1;
public class ChallengeDetailDialogHolder {
+
@BindView(R.id.challenge_not_joined_header)
LinearLayout notJoinedHeader;
@@ -68,11 +73,9 @@ public class ChallengeDetailDialogHolder {
LinearLayout task_group_layout;
private AlertDialog dialog;
- private ApiClient apiClient;
+ private ChallengeRepository challengeRepository;
@Nullable
- private User user;
private Challenge challenge;
- private Action1 challengeJoinedAction;
private Action1 challengeLeftAction;
private Activity context;
@@ -82,8 +85,7 @@ public class ChallengeDetailDialogHolder {
ButterKnife.bind(this, view);
}
- public static void showDialog(Activity activity, ApiClient apiClient, @Nullable User user, Challenge challenge,
- Action1 challengeJoinedAction, Action1 challengeLeftAction) {
+ public static void showDialog(Activity activity, ChallengeRepository challengeRepository, Challenge challenge, Action1 challengeLeftAction) {
View dialogLayout = activity.getLayoutInflater().inflate(R.layout.dialog_challenge_detail, null);
ChallengeDetailDialogHolder challengeDetailDialogHolder = new ChallengeDetailDialogHolder(dialogLayout, activity);
@@ -91,23 +93,21 @@ public class ChallengeDetailDialogHolder {
AlertDialog.Builder builder = new AlertDialog.Builder(activity)
.setView(dialogLayout);
- challengeDetailDialogHolder.bind(builder.show(), apiClient, user, challenge, challengeJoinedAction, challengeLeftAction);
+ challengeDetailDialogHolder.bind(builder.show(), challengeRepository, challenge, challengeLeftAction);
}
- public void bind(AlertDialog dialog, ApiClient apiClient, @Nullable User user, Challenge challenge,
- Action1 challengeJoinedAction, Action1 challengeLeftAction) {
+ public void bind(AlertDialog dialog, ChallengeRepository challengeRepository, Challenge challenge,
+ Action1 challengeLeftAction) {
this.dialog = dialog;
- this.apiClient = apiClient;
- this.user = user;
+ this.challengeRepository = challengeRepository;
this.challenge = challenge;
- this.challengeJoinedAction = challengeJoinedAction;
this.challengeLeftAction = challengeLeftAction;
changeViewsByChallenge(challenge);
}
private void changeViewsByChallenge(Challenge challenge) {
- setJoined(challenge.userId != null && !challenge.userId.isEmpty());
+ setJoined(challenge.isParticipating);
challengeName.setText(EmojiParser.parseEmojis(challenge.name));
challengeDescription.setText(MarkdownParser.parseMarkdown(challenge.description));
@@ -116,7 +116,7 @@ public class ChallengeDetailDialogHolder {
gem_amount.setText(String.valueOf(challenge.prize));
member_count.setText(String.valueOf(challenge.memberCount));
- apiClient.getChallengeTasks(challenge.id)
+ challengeRepository.getChallengeTasks(challenge.id)
.subscribe(taskList -> {
ArrayList todos = new ArrayList<>();
ArrayList habits = new ArrayList<>();
@@ -287,19 +287,7 @@ public class ChallengeDetailDialogHolder {
@OnClick(R.id.challenge_join_btn)
void joinChallenge() {
- this.apiClient.joinChallenge(challenge.id)
- .subscribe(challenge -> {
- if (this.user != null) {
- challenge.userId = this.user.getId();
- }
-
- if (challengeJoinedAction != null) {
- challengeJoinedAction.call(challenge);
- }
-
- changeViewsByChallenge(challenge);
- }, throwable -> {
- });
+ this.challengeRepository.joinChallenge(challenge).subscribe(this::changeViewsByChallenge, throwable -> {});
}
@OnClick(R.id.challenge_leave_btn)
@@ -308,19 +296,11 @@ public class ChallengeDetailDialogHolder {
.setTitle(context.getString(R.string.challenge_leave_title))
.setMessage(context.getString(R.string.challenge_leave_text, challenge.name))
.setPositiveButton(context.getString(R.string.yes), (dialog, which) ->
-
- showRemoveTasksDialog(keepTasks -> this.apiClient.leaveChallenge(challenge.id, new LeaveChallengeBody(keepTasks))
+ showRemoveTasksDialog(keepTasks -> this.challengeRepository.leaveChallenge(challenge, new LeaveChallengeBody(keepTasks))
.subscribe(aVoid -> {
- challenge.userId = null;
-
- if (this.user != null) {
- this.user.resetChallengeList();
- }
-
if (challengeLeftAction != null) {
challengeLeftAction.call(challenge);
}
-
this.dialog.dismiss();
}, throwable -> {
}))).setNegativeButton(context.getString(R.string.no), (dialog, which) -> dialog.dismiss()).show();
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.java
index 28375b78d..87f13125b 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.java
@@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.ui.fragments.social.challenges;
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
@@ -29,9 +30,6 @@ class ChallengeFilterDialogHolder {
@BindView(R.id.challenge_filter_recycler_view)
RecyclerView groupRecyclerView;
- @BindView(R.id.challenge_filter_button_done)
- Button doneButton;
-
@BindView(R.id.challenge_filter_button_all)
Button allButton;
@@ -74,6 +72,7 @@ class ChallengeFilterDialogHolder {
ChallengeFilterOptions currentFilter,
Action1 selectedGroupsCallback) {
this.dialog = dialog;
+ this.dialog.setButton(Dialog.BUTTON_POSITIVE, context.getString(R.string.done), (dialog1, which) -> doneClicked());
this.challengesViewed = challengesViewed;
this.currentFilter = currentFilter;
this.selectedGroupsCallback = selectedGroupsCallback;
@@ -116,8 +115,7 @@ class ChallengeFilterDialogHolder {
return groupMap.values();
}
- @OnClick(R.id.challenge_filter_button_done)
- void doneClicked() {
+ private void doneClicked() {
ChallengeFilterOptions options = new ChallengeFilterOptions();
options.showByGroups = this.adapter.getCheckedEntries();
options.showOwned = checkboxOwned.isChecked();
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.java
index 8e4659c3f..e3795ad5c 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.java
@@ -2,10 +2,9 @@ package com.habitrpg.android.habitica.ui.fragments.social.challenges;
import android.content.Intent;
import android.os.Bundle;
+import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -13,19 +12,18 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.components.AppComponent;
-import com.habitrpg.android.habitica.data.SocialRepository;
+import com.habitrpg.android.habitica.data.ChallengeRepository;
import com.habitrpg.android.habitica.helpers.ReactiveErrorHandler;
import com.habitrpg.android.habitica.models.social.Challenge;
import com.habitrpg.android.habitica.ui.activities.CreateChallengeActivity;
import com.habitrpg.android.habitica.ui.adapter.social.ChallengesListViewAdapter;
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
+import com.habitrpg.android.habitica.ui.helpers.RecyclerViewEmptySupport;
import javax.inject.Inject;
@@ -33,31 +31,21 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import io.realm.RealmResults;
import rx.Observable;
-import rx.functions.Action0;
public class ChallengeListFragment extends BaseMainFragment implements SwipeRefreshLayout.OnRefreshListener {
@Inject
- SocialRepository socialRepository;
+ ChallengeRepository challengeRepository;
- @BindView(R.id.challenge_filter_layout)
- LinearLayout challengeFilterLayout;
-
- @BindView(R.id.action_filter_icon)
- View actionFilterIcon;
-
- @BindView(R.id.challenges_refresh_layout)
+ @BindView(R.id.refresh_layout)
SwipeRefreshLayout swipeRefreshLayout;
-
- @BindView(R.id.challenges_refresh_empty)
- SwipeRefreshLayout swipeRefreshEmptyLayout;
-
- @BindView(R.id.challenges_list)
- RecyclerView recyclerView;
+ @BindView(R.id.recyclerView)
+ RecyclerViewEmptySupport recyclerView;
+ @BindView(R.id.empty_view)
+ public View emptyView;
private ChallengesListViewAdapter challengeAdapter;
private boolean viewUserChallengesOnly;
- private Action0 refreshCallback;
private boolean withFilter;
public void setWithFilter(boolean withFilter){
@@ -68,58 +56,14 @@ public class ChallengeListFragment extends BaseMainFragment implements SwipeRefr
this.viewUserChallengesOnly = only;
}
- public void setRefreshingCallback(Action0 refreshCallback) {
- this.refreshCallback = refreshCallback;
- }
- private List currentChallengesInView;
+ private RealmResults challenges;
private ChallengeFilterOptions lastFilterOptions;
- public void setObservable(Observable> listObservable) {
- listObservable
- .subscribe(challenges -> {
-
- List userChallenges = this.user != null ? this.user.getChallengeList() : new ArrayList<>();
-
- HashSet userChallengesHash = new HashSet<>();
-
- for (Challenge userChallenge : userChallenges) {
- userChallengesHash.add(userChallenge.id);
- }
-
- userChallenges.clear();
-
- for (Challenge challenge : challenges) {
- if (userChallengesHash.contains(challenge.id) && challenge.name != null && !challenge.name.isEmpty()) {
- challenge.userId = this.user.getId();
- userChallenges.add(challenge);
- } else {
- challenge.userId = null;
- }
- }
-
- setRefreshingIfVisible(swipeRefreshLayout, false);
- setRefreshingIfVisible(swipeRefreshEmptyLayout, false);
-
- if (viewUserChallengesOnly) {
- setChallengeEntries(userChallenges);
- } else {
- setChallengeEntries(challenges);
- }
-
-
- }, throwable -> {
- Log.e("ChallengeListFragment", "", throwable);
-
- setRefreshingIfVisible(swipeRefreshLayout, false);
- setRefreshingIfVisible(swipeRefreshEmptyLayout, false);
- });
- }
-
@Override
public void onDestroy() {
- socialRepository.close();
+ challengeRepository.close();
super.onDestroy();
}
@@ -130,17 +74,9 @@ public class ChallengeListFragment extends BaseMainFragment implements SwipeRefr
View v = inflater.inflate(R.layout.fragment_challengeslist, container, false);
unbinder = ButterKnife.bind(this, v);
- challengeAdapter = new ChallengesListViewAdapter(viewUserChallengesOnly, user);
+ challengeAdapter = new ChallengesListViewAdapter(null, true, viewUserChallengesOnly);
swipeRefreshLayout.setOnRefreshListener(this);
- swipeRefreshEmptyLayout.setOnRefreshListener(this);
-
- challengeFilterLayout.setVisibility(withFilter?View.VISIBLE:View.GONE);
- challengeFilterLayout.setClickable(true);
- challengeFilterLayout.setOnClickListener(view -> ChallengeFilterDialogHolder.showDialog(getActivity(), currentChallengesInView, lastFilterOptions, filterOptions -> {
- challengeAdapter.setFilterByGroups(filterOptions);
- this.lastFilterOptions = filterOptions;
- }));
recyclerView.setLayoutManager(new LinearLayoutManager(this.activity));
recyclerView.setAdapter(challengeAdapter);
@@ -148,7 +84,9 @@ public class ChallengeListFragment extends BaseMainFragment implements SwipeRefr
this.recyclerView.setBackgroundResource(R.color.white);
}
- fetchLocalChallenges();
+ recyclerView.setEmptyView(emptyView);
+
+ loadLocalChallenges();
return v;
}
@@ -159,72 +97,36 @@ public class ChallengeListFragment extends BaseMainFragment implements SwipeRefr
@Override
public void onRefresh() {
- setRefreshingIfVisible(swipeRefreshEmptyLayout, true);
- setRefreshingIfVisible(swipeRefreshLayout, true);
-
fetchOnlineChallenges();
}
- private void setRefreshingIfVisible(SwipeRefreshLayout refreshLayout, boolean state) {
- if (refreshLayout != null && refreshLayout.getVisibility() == View.VISIBLE) {
- refreshLayout.setRefreshing(state);
+ private void setRefreshing(boolean state) {
+ if (swipeRefreshLayout != null && swipeRefreshLayout.getVisibility() == View.VISIBLE) {
+ swipeRefreshLayout.setRefreshing(state);
}
}
- private void fetchLocalChallenges() {
- setRefreshingIfVisible(swipeRefreshLayout, true);
-
+ private void loadLocalChallenges() {
Observable> observable;
if (viewUserChallengesOnly && user != null) {
- observable = socialRepository.getUserChallenges(user.getId());
+ observable = challengeRepository.getUserChallenges(user.getId());
} else {
- observable = socialRepository.getChallenges();
+ observable = challengeRepository.getChallenges();
}
- observable.subscribe(challenges -> {
- if (challenges.size() != 0) {
- setChallengeEntries(challenges);
+ observable.first().subscribe(challenges -> {
+ if (challenges.size() == 0) {
+ fetchOnlineChallenges();
}
-
- setRefreshingIfVisible(swipeRefreshLayout, false);
-
- // load online challenges & save to database
- onRefresh();
+ this.challenges = challenges;
+ challengeAdapter.updateData(challenges);
}, ReactiveErrorHandler.handleEmptyError());
}
- private void setChallengeEntries(List challenges) {
- if (swipeRefreshEmptyLayout == null || swipeRefreshLayout == null) {
- return;
- }
- currentChallengesInView = challenges;
-
- if (viewUserChallengesOnly && challenges.size() == 0) {
- swipeRefreshEmptyLayout.setVisibility(View.VISIBLE);
- swipeRefreshLayout.setRefreshing(false);
- swipeRefreshLayout.setVisibility(View.GONE);
- } else {
- swipeRefreshEmptyLayout.setRefreshing(false);
- swipeRefreshEmptyLayout.setVisibility(View.GONE);
- swipeRefreshLayout.setVisibility(View.VISIBLE);
- }
-
- challengeAdapter.setChallenges(challenges);
- }
-
private void fetchOnlineChallenges() {
- if (refreshCallback != null) {
- refreshCallback.call();
- }
- }
-
- public void addItem(Challenge challenge) {
- challengeAdapter.addChallenge(challenge);
- }
-
- public void updateItem(Challenge challenge) {
- challengeAdapter.replaceChallenge(challenge);
+ setRefreshing(true);
+ challengeRepository.retrieveChallenges(user).subscribe(challenges -> setRefreshing(false), throwable -> setRefreshing(false));
}
@Override
@@ -235,7 +137,21 @@ public class ChallengeListFragment extends BaseMainFragment implements SwipeRefr
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_list_challenges, menu);
-}
+
+
+ RelativeLayout badgeLayout = (RelativeLayout) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
+ TextView filterCountTextView = (TextView) badgeLayout.findViewById(R.id.badge_textview);
+ filterCountTextView.setText(null);
+ filterCountTextView.setVisibility(View.GONE);
+ badgeLayout.setOnClickListener(view -> showFilterDialog());
+ }
+
+ private void showFilterDialog() {
+ ChallengeFilterDialogHolder.showDialog(getActivity(),
+ challenges,
+ lastFilterOptions,
+ filterOptions -> this.lastFilterOptions = filterOptions);
+ }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
@@ -248,7 +164,12 @@ public class ChallengeListFragment extends BaseMainFragment implements SwipeRefr
case R.id.action_create_challenge:
Intent intent = new Intent(getActivity(), CreateChallengeActivity.class);
startActivity(intent);
-
+ return true;
+ case R.id.action_reload:
+ fetchOnlineChallenges();
+ return true;
+ case R.id.action_search:
+ showFilterDialog();
return true;
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengesOverviewFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengesOverviewFragment.java
index 53a6438d3..c589385af 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengesOverviewFragment.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengesOverviewFragment.java
@@ -11,34 +11,24 @@ import android.view.ViewGroup;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.components.AppComponent;
-import com.habitrpg.android.habitica.data.SocialRepository;
+import com.habitrpg.android.habitica.data.ChallengeRepository;
import com.habitrpg.android.habitica.events.commands.ShowChallengeDetailActivityCommand;
import com.habitrpg.android.habitica.events.commands.ShowChallengeDetailDialogCommand;
import com.habitrpg.android.habitica.helpers.ReactiveErrorHandler;
-import com.habitrpg.android.habitica.models.social.Challenge;
import com.habitrpg.android.habitica.ui.activities.ChallengeDetailActivity;
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment;
import org.greenrobot.eventbus.Subscribe;
-import java.util.List;
-import java.util.Stack;
-
import javax.inject.Inject;
-import rx.subjects.PublishSubject;
-
public class ChallengesOverviewFragment extends BaseMainFragment {
@Inject
- SocialRepository socialRepository;
+ ChallengeRepository challengeRepository;
public ViewPager viewPager;
public FragmentStatePagerAdapter statePagerAdapter;
- int currentPage;
- private Stack pageHistory;
- private boolean saveToHistory;
- private PublishSubject> getUserChallengesObservable;
private ChallengeListFragment userChallengesFragment;
private ChallengeListFragment availableChallengesFragment;
@@ -53,40 +43,23 @@ public class ChallengesOverviewFragment extends BaseMainFragment {
setViewPagerAdapter();
- getUserChallengesObservable = PublishSubject.create();
-
- subscribeGetChallenges();
-
userChallengesFragment = new ChallengeListFragment();
userChallengesFragment.setUser(this.user);
- userChallengesFragment.setRefreshingCallback(this::subscribeGetChallenges);
- userChallengesFragment.setObservable(getUserChallengesObservable);
userChallengesFragment.setViewUserChallengesOnly(true);
userChallengesFragment.setWithFilter(true);
availableChallengesFragment = new ChallengeListFragment();
availableChallengesFragment.setUser(this.user);
- availableChallengesFragment.setRefreshingCallback(this::subscribeGetChallenges);
- availableChallengesFragment.setObservable(getUserChallengesObservable);
availableChallengesFragment.setViewUserChallengesOnly(false);
-
- pageHistory = new Stack<>();
-
return v;
}
@Override
public void onDestroy() {
- socialRepository.close();
+ challengeRepository.close();
super.onDestroy();
}
- private void subscribeGetChallenges() {
- this.socialRepository.getUserChallenges()
- .subscribe(challenges -> getUserChallengesObservable.onNext(challenges),
- e -> getUserChallengesObservable.onError(e));
- }
-
@Override
public void injectFragment(AppComponent component) {
component.inject(this);
@@ -128,25 +101,6 @@ public class ChallengesOverviewFragment extends BaseMainFragment {
}
};
viewPager.setAdapter(statePagerAdapter);
- viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
-
- @Override
- public void onPageSelected(int newPageId) {
- if (saveToHistory)
- pageHistory.push(currentPage);
-
- currentPage = newPageId;
- }
-
- @Override
- public void onPageScrolled(int arg0, float arg1, int arg2) {
- }
-
- @Override
- public void onPageScrollStateChanged(int arg0) {
- }
- });
- saveToHistory = true;
if (tabLayout != null && viewPager != null) {
tabLayout.setupWithViewPager(viewPager);
@@ -155,17 +109,10 @@ public class ChallengesOverviewFragment extends BaseMainFragment {
@Subscribe
public void onEvent(ShowChallengeDetailDialogCommand cmd) {
- socialRepository.getChallenge(cmd.challengeId).subscribe(challenge -> {
- ChallengeDetailDialogHolder.showDialog(getActivity(), apiClient, user, challenge, challenge1 -> {
- // challenge joined
- userChallengesFragment.addItem(challenge1);
- availableChallengesFragment.updateItem(challenge1);
- }, challenge1 -> {
- // challenge left
- userChallengesFragment.onRefresh();
- availableChallengesFragment.onRefresh();
- });
- }, ReactiveErrorHandler.handleEmptyError());
+ challengeRepository.getChallenge(cmd.challengeId).first().subscribe(challenge -> ChallengeDetailDialogHolder.showDialog(getActivity(), challengeRepository, challenge,
+ challenge1 -> {
+ // challenge left
+ }), ReactiveErrorHandler.handleEmptyError());
}
@Subscribe
@@ -179,18 +126,6 @@ public class ChallengesOverviewFragment extends BaseMainFragment {
getActivity().startActivity(intent);
}
- public boolean onHandleBackPressed() {
- if (!pageHistory.empty()) {
- saveToHistory = false;
- viewPager.setCurrentItem(pageHistory.pop());
- saveToHistory = true;
-
- return true;
- }
-
- return false;
- }
-
@Override
public String customTitle() {
return getString(R.string.challenges);
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/ChallengeListDeserializer.java b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/ChallengeListDeserializer.java
new file mode 100644
index 000000000..c141396dd
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/ChallengeListDeserializer.java
@@ -0,0 +1,57 @@
+package com.habitrpg.android.habitica.utils;
+
+import android.support.annotation.Nullable;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.habitrpg.android.habitica.models.social.Challenge;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+import io.realm.Realm;
+import io.realm.RealmList;
+
+public class ChallengeListDeserializer implements JsonDeserializer> {
+ @Override
+ public List deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+ RealmList challenges = new RealmList<>();
+
+ Realm realm = Realm.getDefaultInstance();
+ List existingChallenges = realm.copyFromRealm(realm.where(Challenge.class).findAll());
+ realm.close();
+
+ for (JsonElement element : json.getAsJsonArray()) {
+ Challenge challenge;
+ if (element.isJsonObject()) {
+ challenge = context.deserialize(element, Challenge.class);
+ Challenge existingChallenge = findExistingChallenge(existingChallenges, challenge.id);
+ if (existingChallenge != null) {
+ challenge.isParticipating = existingChallenge.isParticipating;
+ }
+ } else {
+ challenge = findExistingChallenge(existingChallenges, element.getAsString());
+ if (challenge == null) {
+ challenge = new Challenge();
+ challenge.id = element.getAsString();
+ }
+ challenge.isParticipating = true;
+ }
+ challenges.add(challenge);
+ }
+
+ return challenges;
+ }
+
+ @Nullable
+ private Challenge findExistingChallenge(List existingChallenges, String id) {
+ for (Challenge challenge : existingChallenges) {
+ if (id.equals(challenge.id)) {
+ return challenge;
+ }
+ }
+ return null;
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/UserDeserializer.java b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/UserDeserializer.java
index e723bac62..93f39d8ae 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/UserDeserializer.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/UserDeserializer.java
@@ -8,6 +8,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import com.habitrpg.android.habitica.models.Tag;
import com.habitrpg.android.habitica.models.invitations.Invitations;
+import com.habitrpg.android.habitica.models.social.Challenge;
import com.habitrpg.android.habitica.models.social.UserParty;
import com.habitrpg.android.habitica.models.tasks.TasksOrder;
import com.habitrpg.android.habitica.models.user.Authentication;
@@ -72,7 +73,7 @@ public class UserDeserializer implements JsonDeserializer {
user.setTasksOrder(context.deserialize(obj.get("tasksOrder"), TasksOrder.class));
}
if (obj.has("challenges")) {
- user.setChallenges(context.deserialize(obj.get("challenges"), new TypeToken>() {
+ user.setChallenges(context.deserialize(obj.get("challenges"), new TypeToken>() {
}.getType()));
}
if (obj.has("purchased")) {