fix challenge list

This commit is contained in:
Phillip Thelen 2017-05-04 19:52:42 +02:00
parent 68e3ca7b65
commit cd3bfbcd67
28 changed files with 444 additions and 730 deletions

View file

@ -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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="65dp"
android:orientation="horizontal">
<TextView
style="@style/Title1_WideLetterSpacing"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="2"
android:text="@string/filters"
android:textColor="#000" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_weight="1"
android:gravity="right">
<Button
android:id="@+id/challenge_filter_button_done"
style="@style/Body1_Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/done"
android:textColor="#6133b4"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
@ -60,16 +28,14 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:gravity="center">
<TextView
style="@style/Caption3"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="14dp"
android:layout_weight="2"
android:height="20dp"
android:gravity="center_vertical"
android:text="@string/groups"
android:textAllCaps="true" />
@ -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" />
<Button
android:id="@+id/challenge_filter_button_none"
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/none"
android:textColor="#6133b4"
android:textSize="16sp" />
</LinearLayout>
android:textSize="16sp"
android:padding="0dp"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/challenge_filter_recycler_view"
@ -101,63 +68,32 @@
android:layout_height="wrap_content"
tools:listitem="@layout/dialog_challenge_filter_group_item"
tools:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
style="@style/Caption3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="14dp"
android:layout_weight="2"
android:height="20dp"
android:gravity="center_vertical"
android:text="Ownerchip"
android:text="@string/ownership"
android:textAllCaps="true" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
style="@style/Subheader2"
android:id="@+id/challenge_filter_owned"
android:layout_width="50dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="true"
android:text="" />
<TextView
style="@style/Subheader2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/owned" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:text="@string/owned"
android:textColor="@color/textColorLight"/>
<CheckBox
style="@style/Subheader2"
android:id="@+id/challenge_filter_not_owned"
android:layout_width="50dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="true"
android:text="" />
<TextView
style="@style/Subheader2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/not_owned" />
</LinearLayout>
android:text="@string/not_owned"
android:textColor="@color/textColorLight"/>
</LinearLayout>
</com.habitrpg.android.habitica.ui.MaxHeightLinearLayout>

View file

@ -1,82 +1,29 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:orientation="vertical">
<LinearLayout
android:id="@+id/challenge_filter_layout"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#f9f9f9"
android:orientation="horizontal"
android:padding="16dp">
<ImageView
android:id="@+id/action_filter_icon"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginRight="13dp"
android:src="@drawable/ic_action_filter_list"
android:tint="#80000000"
android:contentDescription="filter icon" />
<TextView
style="@style/Caption2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/filter"
android:textAllCaps="true" />
<ImageView
android:layout_width="18dp"
android:layout_height="18dp"
android:src="@drawable/ic_arrow_drop_down_80000000_24dp"
android:contentDescription="filter icon" />
</LinearLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/challenges.refresh.layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="@+id/challenges.list"
android:layout_height="match_parent">
<com.habitrpg.android.habitica.ui.helpers.RecyclerViewEmptySupport
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:divider="@null"
android:scrollbars="vertical"
android:paddingBottom="?attr/actionBarSize" />
</android.support.v4.widget.SwipeRefreshLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/challenges_refresh_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false">
<LinearLayout
android:id="@+id/challenges.list.empty"
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="48dp"
android:layout_marginRight="48dp"
android:layout_marginTop="65dp"
android:layout_marginTop="32dp"
android:orientation="vertical">
<TextView
@ -100,7 +47,6 @@
android:textColor="#66000000" />
<TextView
android:id="@+id/textView5"
style="@style/Body2"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -111,9 +57,5 @@
android:textColor="#66000000" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
</FrameLayout>
</android.support.v4.widget.SwipeRefreshLayout>

View file

@ -2,7 +2,7 @@
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/refresh.layout"
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

View file

@ -7,4 +7,16 @@
android:id="@+id/action_create_challenge"
android:title="@string/create_challenge"/>
<item
android:id="@+id/action_reload"
android:icon="@drawable/ic_refresh_white"
android:title="@string/action_refresh"
app:showAsAction="never"
android:actionViewClass="android.widget.ImageButton"/>
<item android:id="@+id/action_search"
android:icon="@drawable/ic_action_filter_list"
app:actionLayout="@layout/filter_menu_item"
android:title="@string/filter"
app:showAsAction="ifRoom" />
</menu>

View file

@ -488,101 +488,102 @@
<string name="subscribe_prompt_thanks">For Subscribing you are receiving these useful benefits:</string>
<string name="subscription_status">Subscription Status</string>
<string name="byLeader" >by %s</string>
<string name="challenge_details">Challenge Details</string>
<string name="challenge_leave_title">Leave Challenge</string>
<string name="challenge_leave_text">Are you sure you want to leave the Challenge “%s”?</string>
<string name="challenge_remove_tasks_title">Remove tasks</string>
<string name="challenge_remove_tasks_text">Do you want to remove the tasks?</string>
<string name="remove_tasks">Remove</string>
<string name="keep_tasks">Keep</string>
<string name="my_challenges">My Challenges</string>
<string name="public_challenges">Public</string>
<string name="challenges">Challenges</string>
<string name="daily">Daily</string>
<string name="habit">Habit</string>
<string name="reward">Reward</string>
<string name="todo">To-Do</string>
<string name="official">Official</string>
<string name="participating">Participating</string>
<string name="challenge">Challenge</string>
<string name="go_to_challenge">Go to Challenge</string>
<string name="not_part_of_a_challenge">Youre not part of any Challenges right now!</string>
<string name="join_a_challenge">Join a Challenge to add a curated set of tasks to your list, then compete against other Habiticans to win achievements and even gems!</string>
<string name="check_the_public_challenge_tab">Tap the “Public” tab to find the user-created Challenges that are the best fit for you!</string>
<string name="add_reminder">Add Reminder</string>
<string name="warning">Warning</string>
<string name="open_settings">Open Settings</string>
<string name="dont_keep_activities_warning">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.</string>
<string name="inbox">Inbox</string>
<string name="FAQ">Frequently Asked Questions</string>
<string name="special">Special</string>
<string name="gem_for_gold_description">Because you subscribe to Habitica, you can purchase a number of Gems each month using Gold.</string>
<string name="limited_count" >%d left</string>
<string name="gem_shop">Gem</string>
<string name="mystery_item">Mystery Item</string>
<string name="myster_item_notes">Each month, subscribers will receive a mystery item. This is usually released about one week before the end of the month.</string>
<string name="open">Open</string>
<string name="notification_mystery_item">You open the box and find %s!</string>
<string name="checkInRewardEarned">You earned a %1$s as a reward for your devotion to improving your life.</string>
<string name="nextPrizeUnlocks" tools:ignore="PluralsCandidate">Your next prize unlocks at %1$d Check-Ins</string>
<string name="pending_approval">pending approval</string>
<string name="filters">Filters</string>
<string name="done">Done</string>
<string name="group_tasks_edit_description">Group tasks can not be edited.</string>
<string name="group_tasks_edit_title">Can\'t edit this task</string>
<string name="groups">Groups</string>
<string name="all">All</string>
<string name="none">None</string>
<string name="owned">Owned</string>
<string name="not_owned">Not owned</string>
<string name="new_game">New\nGame</string>
<string name="login_btn_fb">Login with Facebook</string>
<string name="login_btn_google">Login with Google</string>
<string name="action_back">Back</string>
<string name="welcome_text">Oh, you must be new here. Im Justin, Ill be your guide in Habitica.\n\nTo start, youll need to create an avatar.</string>
<string name="randomize">Randomize</string>
<string name="avatar_extras">Extras</string>
<string name="avatar_skin_color">Skin Color</string>
<string name="avatar_hair_color">Hair Color</string>
<string name="avatar_hair_bangs">Bangs</string>
<string name="avatar_hair_ponytail">Ponytail</string>
<string name="avatar_glasses">Glasses</string>
<string name="avatar_wheelchair">Wheelchair</string>
<string name="weak">Weak</string>
<string name="strong">Strong</string>
<string name="gray">Grey</string>
<string name="dated">Dated</string>
<string name="completed">Completed</string>
<string name="setuP_group_other">Other</string>
<string name="clear">Clear</string>
<string name="empty_title_habits">You don\'t have any Habits</string>
<string name="empty_description_habits">Habits are tasks that don\'t have a rigid schedule. You can check them off many times a day, or not at all.</string>
<string name="empty_title_dailies">You don\'t have any Dailies</string>
<string name="empty_description_dailies">Dailies are tasks that repeat on a regular basis. Choose the schedule that works for you!</string>
<string name="empty_title_todos">You don\'t have any To-Dos</string>
<string name="empty_description_todos">To-Dos are tasks that only need to be completed once. Add checklists to your To-Dos to increase their value.</string>
<string name="empty_title_rewards">You don\'t have any Rewards</string>
<string name="reset_walkthrough">Reset Justins Walkthrough</string>
<string name="read_community_guidelines">Please read our Community Guidelines before posting</string>
<string name="maintenance">Maintenance</string>
<string name="reload_content">Reload Content</string>
<string name="dailyDueDefaultView">Set Dailies default to due tab</string>
<string name="dailyDueDefaultViewDescription">With this option set, the Dailies tasks will default to due instead of all</string>
<string name="no_billing_gems">Your device does not have any of the supported payment methods. Please use the habitica website if you want to purchase gems.</string>
<string name="no_billing_subscriptions">Your device does not have any of the supported payment methods. Please use the habitica website if you want to purchase a subscription.</string>
<string name="save">Save</string>
<string name="location">Location</string>
<string name="gem_reward">Gem reward</string>
<string name="tasks">Tasks</string>
<string name="create_challenge">Create challenge</string>
<string name="edit_challenge">Edit Challenge</string>
<string name="challenge_create_error_tavern_one_gem">You need at least 1 gem to create a challenge in Tavern.</string>
<string name="challenge_create_error_enough_gems">You don\'t have enough gems to create a challenge.</string>
<string name="identify_your_challenge_with_a_tag">Identify your challenge with a tag ..</string>
<string name="challenge_create_error_tag">You need a tag to create this Challenge.</string>
<string name="challenge_create_error_no_tasks">You need to add at least one task to create this Challenge.</string>
<string name="challenge_create_error_title">You need a title to create this Challenge.</string>
<string name="description_optional">Description (optional)</string>
<string name="new_challenge_title">New challenge title</string>
<string name="byLeader" >by %s</string>
<string name="challenge_details">Challenge Details</string>
<string name="challenge_leave_title">Leave Challenge</string>
<string name="challenge_leave_text">Are you sure you want to leave the Challenge “%s”?</string>
<string name="challenge_remove_tasks_title">Remove tasks</string>
<string name="challenge_remove_tasks_text">Do you want to remove the tasks?</string>
<string name="remove_tasks">Remove</string>
<string name="keep_tasks">Keep</string>
<string name="my_challenges">My Challenges</string>
<string name="public_challenges">Public</string>
<string name="challenges">Challenges</string>
<string name="daily">Daily</string>
<string name="habit">Habit</string>
<string name="reward">Reward</string>
<string name="todo">To-Do</string>
<string name="official">Official</string>
<string name="participating">Participating</string>
<string name="challenge">Challenge</string>
<string name="go_to_challenge">Go to Challenge</string>
<string name="not_part_of_a_challenge">Youre not part of any Challenges right now!</string>
<string name="join_a_challenge">Join a Challenge to add a curated set of tasks to your list, then compete against other Habiticans to win achievements and even gems!</string>
<string name="check_the_public_challenge_tab">Tap the “Public” tab to find the user-created Challenges that are the best fit for you!</string>
<string name="add_reminder">Add Reminder</string>
<string name="warning">Warning</string>
<string name="open_settings">Open Settings</string>
<string name="dont_keep_activities_warning">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.</string>
<string name="inbox">Inbox</string>
<string name="FAQ">Frequently Asked Questions</string>
<string name="special">Special</string>
<string name="gem_for_gold_description">Because you subscribe to Habitica, you can purchase a number of Gems each month using Gold.</string>
<string name="limited_count" >%d left</string>
<string name="gem_shop">Gem</string>
<string name="mystery_item">Mystery Item</string>
<string name="myster_item_notes">Each month, subscribers will receive a mystery item. This is usually released about one week before the end of the month.</string>
<string name="open">Open</string>
<string name="notification_mystery_item">You open the box and find %s!</string>
<string name="checkInRewardEarned">You earned a %1$s as a reward for your devotion to improving your life.</string>
<string name="nextPrizeUnlocks" tools:ignore="PluralsCandidate">Your next prize unlocks at %1$d Check-Ins</string>
<string name="pending_approval">pending approval</string>
<string name="filters">Filters</string>
<string name="done">Done</string>
<string name="group_tasks_edit_description">Group tasks can not be edited.</string>
<string name="group_tasks_edit_title">Can\'t edit this task</string>
<string name="groups">Groups</string>
<string name="all">All</string>
<string name="none">None</string>
<string name="owned">Owned</string>
<string name="not_owned">Not owned</string>
<string name="new_game">New\nGame</string>
<string name="login_btn_fb">Login with Facebook</string>
<string name="login_btn_google">Login with Google</string>
<string name="action_back">Back</string>
<string name="welcome_text">Oh, you must be new here. Im Justin, Ill be your guide in Habitica.\n\nTo start, youll need to create an avatar.</string>
<string name="randomize">Randomize</string>
<string name="avatar_extras">Extras</string>
<string name="avatar_skin_color">Skin Color</string>
<string name="avatar_hair_color">Hair Color</string>
<string name="avatar_hair_bangs">Bangs</string>
<string name="avatar_hair_ponytail">Ponytail</string>
<string name="avatar_glasses">Glasses</string>
<string name="avatar_wheelchair">Wheelchair</string>
<string name="weak">Weak</string>
<string name="strong">Strong</string>
<string name="gray">Grey</string>
<string name="dated">Dated</string>
<string name="completed">Completed</string>
<string name="setuP_group_other">Other</string>
<string name="clear">Clear</string>
<string name="empty_title_habits">You don\'t have any Habits</string>
<string name="empty_description_habits">Habits are tasks that don\'t have a rigid schedule. You can check them off many times a day, or not at all.</string>
<string name="empty_title_dailies">You don\'t have any Dailies</string>
<string name="empty_description_dailies">Dailies are tasks that repeat on a regular basis. Choose the schedule that works for you!</string>
<string name="empty_title_todos">You don\'t have any To-Dos</string>
<string name="empty_description_todos">To-Dos are tasks that only need to be completed once. Add checklists to your To-Dos to increase their value.</string>
<string name="empty_title_rewards">You don\'t have any Rewards</string>
<string name="reset_walkthrough">Reset Justins Walkthrough</string>
<string name="read_community_guidelines">Please read our Community Guidelines before posting</string>
<string name="maintenance">Maintenance</string>
<string name="reload_content">Reload Content</string>
<string name="dailyDueDefaultView">Set Dailies default to due tab</string>
<string name="dailyDueDefaultViewDescription">With this option set, the Dailies tasks will default to due instead of all</string>
<string name="no_billing_gems">Your device does not have any of the supported payment methods. Please use the habitica website if you want to purchase gems.</string>
<string name="no_billing_subscriptions">Your device does not have any of the supported payment methods. Please use the habitica website if you want to purchase a subscription.</string>
<string name="save">Save</string>
<string name="location">Location</string>
<string name="gem_reward">Gem reward</string>
<string name="tasks">Tasks</string>
<string name="create_challenge">Create challenge</string>
<string name="edit_challenge">Edit Challenge</string>
<string name="challenge_create_error_tavern_one_gem">You need at least 1 gem to create a challenge in Tavern.</string>
<string name="challenge_create_error_enough_gems">You don\'t have enough gems to create a challenge.</string>
<string name="identify_your_challenge_with_a_tag">Identify your challenge with a tag ..</string>
<string name="challenge_create_error_tag">You need a tag to create this Challenge.</string>
<string name="challenge_create_error_no_tasks">You need to add at least one task to create this Challenge.</string>
<string name="challenge_create_error_title">You need a title to create this Challenge.</string>
<string name="description_optional">Description (optional)</string>
<string name="new_challenge_title">New challenge title</string>
<string name="ownership">Ownership</string>
</resources>

View file

@ -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<HabitResponse<TaskDirectionData>> postTaskDirection(@Path("id") String id, @Path("direction") String direction);
@POST("tasks/{id}/move/to/{position}")
Observable<HabitResponse<ArrayList<String>>> postTaskNewPosition(@Path("id") String id, @Path("position") String position);
Observable<HabitResponse<List<String>>> postTaskNewPosition(@Path("id") String id, @Path("position") String position);
@POST("tasks/{taskId}/checklist/{itemId}/score")
Observable<HabitResponse<Task>> scoreChecklistItem(@Path("taskId") String taskId, @Path("itemId") String itemId);
@ -273,7 +272,7 @@ public interface ApiService {
/* challenges api */
@GET("challenges/user")
Observable<HabitResponse<ArrayList<Challenge>>> getUserChallenges();
Observable<HabitResponse<List<Challenge>>> getUserChallenges();
@GET("tasks/challenge/{challengeId}")
Observable<HabitResponse<TaskList>> getChallengeTasks(@Path("challengeId") String challengeId);

View file

@ -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);
}

View file

@ -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<Challenge> updateChallenge(Challenge challenge, List<Task> fullTaskList,
List<Task> addedTaskList, List<Task> updatedTaskList, List<String> removedTaskList);
Observable<Void> deleteChallenge(String challengeId);
void setUsersGroups(List<Group> groups);
Observable<RealmResults<Challenge>> getChallenges();
Observable<RealmResults<Challenge>> getUserChallenges(String userId);
Observable<List<Group>> getLocalGroups();
Observable<List<Challenge>> retrieveChallenges(User user);
Observable<Void> leaveChallenge(Challenge challenge, LeaveChallengeBody leaveChallengeBody);
Observable<Challenge> joinChallenge(Challenge challenge);
}

View file

@ -38,7 +38,7 @@ public interface SocialRepository extends BaseRepository {
Observable<Void> updateGroup(Group group);
Observable<List<Group>> retrieveGroups(String type);
Observable<List<Group>> getGroups(String type);
Observable<RealmResults<Group>> getGroups(String type);
Observable<PostChatMessageResult> postPrivateMessage(HashMap<String, String> messageObject);
Observable<PostChatMessageResult> postPrivateMessage(String recipientId, String message);
@ -52,10 +52,5 @@ public interface SocialRepository extends BaseRepository {
Observable<User> getMember(String userId);
Observable<Challenge> getChallenge(String challengeId);
Observable<RealmResults<Challenge>> getChallenges();
Observable<RealmResults<Challenge>> getUserChallenges(String id);
Observable<Void> markPrivateMessagesRead(User user);
}

View file

@ -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<Throwable>, ApiClient {
}
public static GsonConverterFactory createGsonFactory() {
Type taskTagClassListType = new TypeToken<RealmList<Tag>>() {
}.getType();
Type skillListType = new TypeToken<List<Skill>>() {
}.getType();
Type customizationListType = new TypeToken<RealmList<Customization>>() {
}.getType();
Type tutorialStepListType = new TypeToken<RealmList<TutorialStep>>() {
}.getType();
Type faqArticleListType = new TypeToken<RealmList<FAQArticle>>() {
}.getType();
Type itemDataListType = new TypeToken<RealmList<Equipment>>() {
}.getType();
Type eggListType = new TypeToken<RealmList<Egg>>() {
}.getType();
Type foodListType = new TypeToken<RealmList<Food>>() {
}.getType();
Type hatchingPotionListType = new TypeToken<RealmList<HatchingPotion>>() {
}.getType();
Type questContentListType = new TypeToken<RealmList<QuestContent>>() {
}.getType();
Type petMapType = new TypeToken<Map<String, Pet>>() {
}.getType();
Type mountMapType = new TypeToken<Map<String, Mount>>() {
}.getType();
Type petListType = new TypeToken<RealmList<Pet>>() {
}.getType();
Type mountListType = new TypeToken<RealmList<Mount>>() {
}.getType();
Type questCollectListType = new TypeToken<RealmList<QuestCollect>>() {
}.getType();
Type chatMessageListType = new TypeToken<RealmList<ChatMessage>>() {
}.getType();
Type taskTagClassListType = new TypeToken<RealmList<Tag>>() {}.getType();
Type skillListType = new TypeToken<List<Skill>>() {}.getType();
Type customizationListType = new TypeToken<RealmList<Customization>>() {}.getType();
Type tutorialStepListType = new TypeToken<RealmList<TutorialStep>>() {}.getType();
Type faqArticleListType = new TypeToken<RealmList<FAQArticle>>() {}.getType();
Type itemDataListType = new TypeToken<RealmList<Equipment>>() {}.getType();
Type eggListType = new TypeToken<RealmList<Egg>>() {}.getType();
Type foodListType = new TypeToken<RealmList<Food>>() {}.getType();
Type hatchingPotionListType = new TypeToken<RealmList<HatchingPotion>>() {}.getType();
Type questContentListType = new TypeToken<RealmList<QuestContent>>() {}.getType();
Type petMapType = new TypeToken<Map<String, Pet>>() {}.getType();
Type mountMapType = new TypeToken<Map<String, Mount>>() {}.getType();
Type petListType = new TypeToken<RealmList<Pet>>() {}.getType();
Type mountListType = new TypeToken<RealmList<Mount>>() {}.getType();
Type questCollectListType = new TypeToken<RealmList<QuestCollect>>() {}.getType();
Type chatMessageListType = new TypeToken<RealmList<ChatMessage>>() {}.getType();
Type challengeListType = new TypeToken<List<Challenge>>() {}.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<Throwable>, 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);

View file

@ -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<ChallengeLocalRe
}
@Override
public void setUsersGroups(List<Group> groups) {
localRepository.setUsersGroups(groups);
public Observable<RealmResults<Challenge>> getChallenges() {
return localRepository.getChallenges();
}
@Override
public Observable<List<Group>> getLocalGroups() {
return localRepository.getGroups();
public Observable<RealmResults<Challenge>> getUserChallenges(String userId) {
return localRepository.getUserChallenges(userId);
}
@Override
public Observable<List<Challenge>> retrieveChallenges(User user) {
return apiClient.getUserChallenges()
.doOnNext(challenges -> localRepository.saveChallenges(user, challenges));
}
@Override
public Observable<Void> leaveChallenge(Challenge challenge, LeaveChallengeBody leaveChallengeBody) {
return apiClient.leaveChallenge(challenge.id, leaveChallengeBody)
.doOnNext(aVoid -> localRepository.setParticipating(challenge, false));
}
@Override
public Observable<Challenge> joinChallenge(Challenge challenge) {
return apiClient.joinChallenge(challenge.id)
.doOnNext(aVoid -> localRepository.setParticipating(challenge, true));
}
}

View file

@ -106,8 +106,8 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl<SocialLocalReposito
}
@Override
public Observable<List<Group>> getGroups(String type) {
return retrieveGroups(type);
public Observable<RealmResults<Group>> getGroups(String type) {
return localRepository.getGroups(type);
}
@Override
@ -143,21 +143,6 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl<SocialLocalReposito
return apiClient.getMember(userId);
}
@Override
public Observable<Challenge> getChallenge(String challengeId) {
return localRepository.getChallenge(challengeId);
}
@Override
public Observable<RealmResults<Challenge>> getChallenges() {
return localRepository.getChallenges();
}
@Override
public Observable<RealmResults<Challenge>> getUserChallenges(String userId) {
return localRepository.getUserChallenges(userId);
}
@Override
public Observable<Void> markPrivateMessagesRead(User user) {
return apiClient.markPrivateMessagesRead()

View file

@ -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<Challenge> getChallenge(String id);
Observable<List<Task>> getTasks(Challenge challenge);
void setUsersGroups(List<Group> group);
Observable<RealmResults<Challenge>> getChallenges();
Observable<List<Group>> getGroups();
Observable<RealmResults<Challenge>> getUserChallenges(String userId);
void saveChallenges(User user, List<Challenge> challenges);
void setParticipating(Challenge challenge, boolean isParticipating);
}

View file

@ -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<Challenge> getChallenge(String challengeId);
Observable<RealmResults<Challenge>> getChallenges();
Observable<RealmResults<Challenge>> getUserChallenges(String userId);
Observable<RealmResults<Group>> getGroups(String type);
}

View file

@ -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<Group> groups) {
public Observable<RealmResults<Challenge>> getChallenges() {
return realm.where(Challenge.class)
.isNotNull("name")
.findAllSortedAsync("memberCount", Sort.DESCENDING)
.asObservable()
.filter(RealmResults::isLoaded);
}
@Override
public Observable<List<Group>> getGroups() {
return null;
public Observable<RealmResults<Challenge>> 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<Challenge> challenges) {
realm.executeTransactionAsync(realm1 -> realm1.copyToRealmOrUpdate(challenges));
}
@Override
public void setParticipating(Challenge challenge, boolean isParticipating) {
realm.executeTransaction(realm1 -> challenge.isParticipating = isParticipating);
}
}

View file

@ -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<Challenge> getChallenge(String challengeId) {
return realm.where(Challenge.class)
.equalTo("id", challengeId)
.findFirstAsync()
.asObservable()
.filter(realmObject -> realmObject.isLoaded())
.cast(Challenge.class);
}
@Override
public Observable<RealmResults<Challenge>> getChallenges() {
return realm.where(Challenge.class)
.isNotNull("name")
.findAll()
.asObservable()
.filter(RealmResults::isLoaded);
}
@Override
public Observable<RealmResults<Challenge>> getUserChallenges(String userId) {
return realm.where(Challenge.class)
.isNotNull("name")
.equalTo("userId", userId)
.findAll()
public Observable<RealmResults<Group>> getGroups(String type) {
return realm.where(Group.class)
.equalTo("type", type)
.findAllAsync()
.asObservable()
.filter(RealmResults::isLoaded);
}

View file

@ -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<String, String[]> getTasksOrder() {
HashMap<String, String[]> map = new HashMap();

View file

@ -23,8 +23,6 @@ import io.realm.annotations.PrimaryKey;
public class User extends RealmObject {
@Ignore
List<Challenge> challengeList;
@Ignore
public TaskList tasks;
@ -54,21 +52,7 @@ public class User extends RealmObject {
@Ignore
private TasksOrder tasksOrder;
@Ignore
private List<String> challenges;
public List<Challenge> getChallengeList() {
return challengeList;
}
public void setChallengeList(List<Challenge> challenges) {
this.challengeList = challenges;
}
public void resetChallengeList() {
challengeList = null;
}
private RealmList<Challenge> challenges;
public Preferences getPreferences() {
return preferences;
@ -248,14 +232,6 @@ public class User extends RealmObject {
this.pushDevices = pushDevices;
}
public List<String> getChallenges() {
return challenges;
}
public void setChallenges(List<String> challenges) {
this.challenges = challenges;
}
public List<String> getAvatarLayerNames() {
List<String> layerNames = new ArrayList<String>();
@ -467,4 +443,12 @@ public class User extends RealmObject {
public void setTags(RealmList<Tag> tags) {
this.tags = tags;
}
public RealmList<Challenge> getChallenges() {
return challenges;
}
public void setChallenges(RealmList<Challenge> challenges) {
this.challenges = challenges;
}
}

View file

@ -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<Task> 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());
}
}

View file

@ -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<Group> {
public GroupArrayAdapter(@NonNull Context context) {
GroupArrayAdapter(@NonNull Context context) {
super(context, android.R.layout.simple_spinner_item);
}

View file

@ -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<ChallengesListViewAdapter.ChallengeViewHolder> {
private List<Challenge> challenges = new ArrayList<>();
private List<Challenge> challengesSource = new ArrayList<>();
public class ChallengesListViewAdapter extends RealmRecyclerViewAdapter<Challenge, ChallengesListViewAdapter.ChallengeViewHolder> {
private boolean viewUserChallengesOnly;
@Nullable
private User user;
public ChallengesListViewAdapter(boolean viewUserChallengesOnly, @Nullable User user) {
public ChallengesListViewAdapter(@Nullable OrderedRealmCollection<Challenge> data, boolean autoUpdate, boolean viewUserChallengesOnly) {
super(data, autoUpdate);
this.viewUserChallengesOnly = viewUserChallengesOnly;
this.user = user;
}
public void setChallenges(List<Challenge> 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<ChallengesLi
@Override
public void onBindViewHolder(ChallengeViewHolder holder, int position) {
holder.bind(challenges.get(position));
}
@Override
public int getItemCount() {
return challenges.size();
}
public void addChallenge(Challenge challenge) {
challenges.add(challenge);
notifyDataSetChanged();
}
public void replaceChallenge(Challenge challenge) {
int index = challenges.indexOf(challenge);
if (index == -1) {
for (int i = 0; i < challenges.size(); i++) {
if (challenges.get(i).id.equals(challenge.id)) {
index = i;
break;
}
}
}
if (index != -1) {
challenges.set(index, challenge);
notifyItemChanged(index);
}
holder.bind(getData().get(position));
}
public static class ChallengeViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@ -175,14 +114,13 @@ public class ChallengesListViewAdapter extends RecyclerView.Adapter<ChallengesLi
challengeDescription.setText(challenge.groupName);
officialChallengeLayout.setVisibility(challenge.official ? View.VISIBLE : View.GONE);
boolean userIdExists = challenge.userId != null && !challenge.userId.isEmpty();
if (viewUserChallengesOnly) {
leaderParticipantLayout.setVisibility(View.GONE);
challengeParticipatingTextView.setVisibility(View.GONE);
arrowImage.setVisibility(View.VISIBLE);
} else {
challengeParticipatingTextView.setVisibility(userIdExists ? View.VISIBLE : View.GONE);
challengeParticipatingTextView.setVisibility(challenge.isParticipating ? View.VISIBLE : View.GONE);
leaderName.setText(itemView.getContext().getString(R.string.byLeader, challenge.leaderName));
participantCount.setText(String.valueOf(challenge.memberCount));

View file

@ -93,10 +93,7 @@ public class GuildsOverviewFragment extends BaseMainFragment implements View.OnC
if (swipeRefreshLayout != null) {
swipeRefreshLayout.setRefreshing(false);
}
challengeRepository.setUsersGroups(groups);
}, throwable -> {
});
}, throwable -> {});
}
}

View file

@ -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<Challenge> challengeJoinedAction;
private Action1<Challenge> 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<Challenge> challengeJoinedAction, Action1<Challenge> challengeLeftAction) {
public static void showDialog(Activity activity, ChallengeRepository challengeRepository, Challenge challenge, Action1<Challenge> 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<Challenge> challengeJoinedAction, Action1<Challenge> challengeLeftAction) {
public void bind(AlertDialog dialog, ChallengeRepository challengeRepository, Challenge challenge,
Action1<Challenge> 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<Task> todos = new ArrayList<>();
ArrayList<Task> 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();

View file

@ -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<ChallengeFilterOptions> 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();

View file

@ -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<Challenge> currentChallengesInView;
private RealmResults<Challenge> challenges;
private ChallengeFilterOptions lastFilterOptions;
public void setObservable(Observable<List<Challenge>> listObservable) {
listObservable
.subscribe(challenges -> {
List<Challenge> userChallenges = this.user != null ? this.user.getChallengeList() : new ArrayList<>();
HashSet<String> 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<RealmResults<Challenge>> 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<Challenge> 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;
}

View file

@ -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<Integer> pageHistory;
private boolean saveToHistory;
private PublishSubject<List<Challenge>> 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);

View file

@ -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<List<Challenge>> {
@Override
public List<Challenge> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
RealmList<Challenge> challenges = new RealmList<>();
Realm realm = Realm.getDefaultInstance();
List<Challenge> 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<Challenge> existingChallenges, String id) {
for (Challenge challenge : existingChallenges) {
if (id.equals(challenge.id)) {
return challenge;
}
}
return null;
}
}

View file

@ -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> {
user.setTasksOrder(context.deserialize(obj.get("tasksOrder"), TasksOrder.class));
}
if (obj.has("challenges")) {
user.setChallenges(context.deserialize(obj.get("challenges"), new TypeToken<List<String>>() {
user.setChallenges(context.deserialize(obj.get("challenges"), new TypeToken<List<Challenge>>() {
}.getType()));
}
if (obj.has("purchased")) {