mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-22 21:57:11 +00:00
Implement first version of achievement screen
This commit is contained in:
parent
ec14b054ca
commit
2ffa14907e
43 changed files with 672 additions and 70 deletions
|
|
@ -150,7 +150,7 @@ android {
|
|||
buildConfigField "String", "TESTING_LEVEL", "\"production\""
|
||||
multiDexEnabled true
|
||||
|
||||
versionCode 2140
|
||||
versionCode 2141
|
||||
versionName "1.10"
|
||||
}
|
||||
|
||||
|
|
|
|||
4
Habitica/proguard-rules.pro
vendored
4
Habitica/proguard-rules.pro
vendored
|
|
@ -63,8 +63,8 @@
|
|||
-keep class * implements com.google.gson.JsonSerializer
|
||||
-keep class * implements com.google.gson.JsonDeserializer
|
||||
|
||||
#keep models
|
||||
-keep class com.habitrpg.android.habitica.models.** { *; }
|
||||
#keep Habitica code
|
||||
-keep class com.habitrpg.android.habitica.** { *; }
|
||||
|
||||
#realm
|
||||
-keep class io.realm.annotations.RealmModule
|
||||
|
|
|
|||
5
Habitica/res/drawable/achievement_badge_bg.xml
Normal file
5
Habitica/res/drawable/achievement_badge_bg.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<solid android:color="@color/gray_300" />
|
||||
<corners android:radius="12dp" />
|
||||
</shape>
|
||||
5
Habitica/res/drawable/achievement_section_badge_bg.xml
Normal file
5
Habitica/res/drawable/achievement_section_badge_bg.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<solid android:color="@color/gray_700" />
|
||||
<corners android:radius="12dp" />
|
||||
</shape>
|
||||
4
Habitica/res/drawable/circle_gray600.xml
Normal file
4
Habitica/res/drawable/circle_gray600.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<solid android:color="@color/gray_600" />
|
||||
</shape>
|
||||
5
Habitica/res/drawable/ic_round_view_list_24px.xml
Normal file
5
Habitica/res/drawable/ic_round_view_list_24px.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFFFFFFF" android:pathData="M4,14h2c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1L4,10c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1zM4,19h2c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1L4,15c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1zM4,9h2c0.55,0 1,-0.45 1,-1L7,6c0,-0.55 -0.45,-1 -1,-1L4,5c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1zM9,14h10c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1L9,10c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1zM9,19h10c0.55,0 1,-0.45 1,-1v-2c0,-0.55 -0.45,-1 -1,-1L9,15c-0.55,0 -1,0.45 -1,1v2c0,0.55 0.45,1 1,1zM8,6v2c0,0.55 0.45,1 1,1h10c0.55,0 1,-0.45 1,-1L20,6c0,-0.55 -0.45,-1 -1,-1L9,5c-0.55,0 -1,0.45 -1,1z"/>
|
||||
</vector>
|
||||
5
Habitica/res/drawable/ic_round_view_module_24px.xml
Normal file
5
Habitica/res/drawable/ic_round_view_module_24px.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFFFFFFF" android:pathData="M5,11h3c0.55,0 1,-0.45 1,-1L9,6c0,-0.55 -0.45,-1 -1,-1L5,5c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1zM5,18h3c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1L5,12c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1zM11,18h3c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1zM17,18h3c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1zM11,11h3c0.55,0 1,-0.45 1,-1L15,6c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1zM16,6v4c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1L21,6c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1z"/>
|
||||
</vector>
|
||||
61
Habitica/res/layout/achievement_grid_item.xml
Normal file
61
Habitica/res/layout/achievement_grid_item.xml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingTop="13dp"
|
||||
android:paddingBottom="13dp"
|
||||
tools:background="@color/white">
|
||||
<LinearLayout
|
||||
android:id="@+id/achievement_container"
|
||||
android:layout_width="156dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/layout_rounded_bg_gray_700"
|
||||
android:clipChildren="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_margin="4dp">
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="66dp">
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/achievement_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_gravity="center"/>
|
||||
</FrameLayout>
|
||||
<TextView
|
||||
android:id="@+id/achievement_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="40dp"
|
||||
style="@style/Body1"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/gray_100"
|
||||
android:background="@color/gray_600"
|
||||
android:paddingStart="@dimen/spacing_medium"
|
||||
android:paddingEnd="@dimen/spacing_medium"
|
||||
android:paddingTop="@dimen/spacing_small"
|
||||
android:paddingBottom="@dimen/spacing_small"/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/achievement_count_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:minWidth="24dp"
|
||||
android:background="@drawable/achievement_badge_bg"
|
||||
android:gravity="center"
|
||||
tools:text="1"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignStart="@id/achievement_container"
|
||||
android:layout_marginStart="-4dp"/>
|
||||
</RelativeLayout>
|
||||
53
Habitica/res/layout/achievement_list_item.xml
Normal file
53
Habitica/res/layout/achievement_list_item.xml
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingTop="13dp"
|
||||
android:paddingBottom="13dp">
|
||||
<RelativeLayout
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="86dp">
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/achievement_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_centerInParent="true"/>
|
||||
<TextView
|
||||
android:id="@+id/achievement_count_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:minWidth="24dp"
|
||||
android:background="@drawable/achievement_badge_bg"
|
||||
android:gravity="center"
|
||||
tools:text="1"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginStart="13dp"
|
||||
android:layout_marginTop="0dp"/>
|
||||
</RelativeLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/achievement_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Body1"
|
||||
android:textColor="@color/gray_100"/>
|
||||
<TextView
|
||||
android:id="@+id/achievement_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Caption3"
|
||||
android:textColor="@color/gray_100"/>
|
||||
</LinearLayout>r
|
||||
</LinearLayout>
|
||||
28
Habitica/res/layout/achievement_quest_item.xml
Normal file
28
Habitica/res/layout/achievement_quest_item.xml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingTop="13dp"
|
||||
android:paddingBottom="13dp">
|
||||
<TextView
|
||||
android:id="@+id/achievement_count_label"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/gray_200"
|
||||
style="@style/Body1"
|
||||
android:background="@drawable/circle_gray600"
|
||||
tools:text="12"
|
||||
android:layout_marginStart="35dp"
|
||||
android:layout_marginEnd="25dp"/>
|
||||
<TextView
|
||||
android:id="@+id/achievement_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Body1"
|
||||
android:textColor="@color/gray_100"
|
||||
tools:text="This is the quest title"/>
|
||||
</LinearLayout>
|
||||
30
Habitica/res/layout/achievement_section_header.xml
Normal file
30
Habitica/res/layout/achievement_section_header.xml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="@dimen/spacing_medium"
|
||||
android:paddingLeft="@dimen/spacing_large"
|
||||
android:paddingRight="@dimen/spacing_large">
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Overline"
|
||||
tools:text="Title"/>
|
||||
<TextView
|
||||
android:id="@+id/count_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:minWidth="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/achievement_section_badge_bg"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:textColor="@color/gray_200"
|
||||
style="@style/Overline"
|
||||
tools:text="1"/>
|
||||
</LinearLayout>
|
||||
|
|
@ -289,4 +289,13 @@
|
|||
<action
|
||||
android:id="@+id/openProfileActivity"
|
||||
app:destination="@id/fullProfileActivity" />
|
||||
<fragment
|
||||
android:id="@+id/achievementsFragment"
|
||||
android:name="com.habitrpg.android.habitica.ui.fragments.AchievementsFragment"
|
||||
android:label="@string/sidebar_achievements" >
|
||||
<argument
|
||||
android:name="userID"
|
||||
app:argType="string"
|
||||
app:nullable="true" />
|
||||
</fragment>
|
||||
</navigation>
|
||||
|
|
@ -919,4 +919,10 @@
|
|||
<string name="pin">Pin</string>
|
||||
<string name="unpin">Unpin</string>
|
||||
<string name="take_me_back">Take me Back</string>
|
||||
<string name="sidebar_achievements">Achievements</string>
|
||||
<string name="basic_achievements">Basic Achievements</string>
|
||||
<string name="seasonal_achievements">Seasonal Achievements</string>
|
||||
<string name="special_achievements">Special Achievements</string>
|
||||
<string name="switch_to_list_view">Switch to list view</string>
|
||||
<string name="switch_to_grid_view">Switch to grid view</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -121,4 +121,9 @@
|
|||
<item name="android:textSize">12sp</item>
|
||||
<item name="android:letterSpacing">0.035</item>
|
||||
</style>
|
||||
<style name="Overline">
|
||||
<item name="android:fontFamily">@string/font_family_regular</item>
|
||||
<item name="android:textSize">10sp</item>
|
||||
<item name="android:textAllCaps">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.habitrpg.android.habitica.api;
|
||||
|
||||
import com.habitrpg.android.habitica.models.AchievementResult;
|
||||
import com.habitrpg.android.habitica.models.Achievement;
|
||||
import com.habitrpg.android.habitica.models.ContentResult;
|
||||
import com.habitrpg.android.habitica.models.LeaveChallengeBody;
|
||||
import com.habitrpg.android.habitica.models.PurchaseValidationRequest;
|
||||
|
|
@ -284,7 +284,7 @@ public interface ApiService {
|
|||
Flowable<HabitResponse<Member>> getMemberWithUsername(@Path("username") String username);
|
||||
|
||||
@GET("members/{mid}/achievements")
|
||||
Flowable<HabitResponse<AchievementResult>> getMemberAchievements(@Path("mid") String memberId);
|
||||
Flowable<HabitResponse<List<Achievement>>> getMemberAchievements(@Path("mid") String memberId);
|
||||
|
||||
@POST("members/send-private-message")
|
||||
Flowable<HabitResponse<PostChatMessageResult>> postPrivateMessage(@Body Map<String, String> messageDetails);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.habitrpg.android.habitica.api;
|
|||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.habitrpg.android.habitica.models.Achievement;
|
||||
import com.habitrpg.android.habitica.models.ContentResult;
|
||||
import com.habitrpg.android.habitica.models.FAQArticle;
|
||||
import com.habitrpg.android.habitica.models.Skill;
|
||||
|
|
@ -11,8 +12,6 @@ import com.habitrpg.android.habitica.models.TutorialStep;
|
|||
import com.habitrpg.android.habitica.models.WorldState;
|
||||
import com.habitrpg.android.habitica.models.inventory.Customization;
|
||||
import com.habitrpg.android.habitica.models.inventory.Equipment;
|
||||
import com.habitrpg.android.habitica.models.inventory.Mount;
|
||||
import com.habitrpg.android.habitica.models.inventory.Pet;
|
||||
import com.habitrpg.android.habitica.models.inventory.Quest;
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestCollect;
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestDropItem;
|
||||
|
|
@ -29,6 +28,7 @@ import com.habitrpg.android.habitica.models.user.OwnedMount;
|
|||
import com.habitrpg.android.habitica.models.user.OwnedPet;
|
||||
import com.habitrpg.android.habitica.models.user.Purchases;
|
||||
import com.habitrpg.android.habitica.models.user.User;
|
||||
import com.habitrpg.android.habitica.utils.AchievementListDeserializer;
|
||||
import com.habitrpg.android.habitica.utils.BooleanAsIntAdapter;
|
||||
import com.habitrpg.android.habitica.utils.ChallengeDeserializer;
|
||||
import com.habitrpg.android.habitica.utils.ChallengeListDeserializer;
|
||||
|
|
@ -53,15 +53,14 @@ import com.habitrpg.android.habitica.utils.QuestDropItemsListSerialization;
|
|||
import com.habitrpg.android.habitica.utils.SkillDeserializer;
|
||||
import com.habitrpg.android.habitica.utils.TaskListDeserializer;
|
||||
import com.habitrpg.android.habitica.utils.TaskSerializer;
|
||||
import com.habitrpg.android.habitica.utils.TutorialStepListDeserializer;
|
||||
import com.habitrpg.android.habitica.utils.TaskTagDeserializer;
|
||||
import com.habitrpg.android.habitica.utils.TutorialStepListDeserializer;
|
||||
import com.habitrpg.android.habitica.utils.UserDeserializer;
|
||||
import com.habitrpg.android.habitica.utils.WorldStateSerialization;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.realm.RealmList;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
|
@ -83,6 +82,7 @@ public class GSonFactoryCreator {
|
|||
Type ownedItemListType = new TypeToken<RealmList<OwnedItem>>() {}.getType();
|
||||
Type ownedPetListType = new TypeToken<RealmList<OwnedPet>>() {}.getType();
|
||||
Type ownedMountListType = new TypeToken<RealmList<OwnedMount>>() {}.getType();
|
||||
Type achievementsListType = new TypeToken<List<Achievement>>() {}.getType();
|
||||
|
||||
|
||||
//Exclusion strategy needed for DBFlow https://github.com/Raizlabs/DBFlow/issues/121
|
||||
|
|
@ -113,6 +113,7 @@ public class GSonFactoryCreator {
|
|||
.registerTypeAdapter(ownedItemListType, new OwnedItemListDeserializer())
|
||||
.registerTypeAdapter(ownedPetListType, new OwnedPetListDeserializer())
|
||||
.registerTypeAdapter(ownedMountListType, new OwnedMountListDeserializer())
|
||||
.registerTypeAdapter(achievementsListType, new AchievementListDeserializer())
|
||||
.registerTypeAdapter(Quest.class, new QuestDeserializer())
|
||||
.registerTypeAdapter(Member.class, new MemberSerialization())
|
||||
.registerTypeAdapter(WorldState.class, new WorldStateSerialization())
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import com.habitrpg.android.habitica.ui.adapter.tasks.HabitsRecyclerViewAdapter;
|
|||
import com.habitrpg.android.habitica.ui.adapter.tasks.RewardsRecyclerViewAdapter;
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.TodosRecyclerViewAdapter;
|
||||
import com.habitrpg.android.habitica.ui.fragments.AboutFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.AchievementsFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.GemsPurchaseFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.NavigationDrawerFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.NewsFragment;
|
||||
|
|
@ -314,4 +315,6 @@ public interface AppComponent {
|
|||
void inject(@NotNull ReportMessageActivity reportMessageActivity);
|
||||
|
||||
void inject(@NotNull GuildDetailFragment guildDetailFragment);
|
||||
|
||||
void inject(@NotNull AchievementsFragment achievementsFragment);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ interface ApiClient {
|
|||
fun getMember(memberId: String): Flowable<Member>
|
||||
fun getMemberWithUsername(username: String): Flowable<Member>
|
||||
|
||||
fun getMemberAchievements(memberId: String): Flowable<AchievementResult>
|
||||
fun getMemberAchievements(memberId: String): Flowable<List<Achievement>>
|
||||
|
||||
fun postPrivateMessage(messageDetails: Map<String, String>): Flowable<PostChatMessageResult>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,11 @@
|
|||
package com.habitrpg.android.habitica.data
|
||||
|
||||
import com.habitrpg.android.habitica.models.inventory.Egg
|
||||
import com.habitrpg.android.habitica.models.inventory.Equipment
|
||||
import com.habitrpg.android.habitica.models.inventory.Food
|
||||
import com.habitrpg.android.habitica.models.inventory.HatchingPotion
|
||||
import com.habitrpg.android.habitica.models.inventory.Item
|
||||
import com.habitrpg.android.habitica.models.inventory.Mount
|
||||
import com.habitrpg.android.habitica.models.inventory.Pet
|
||||
import com.habitrpg.android.habitica.models.inventory.Quest
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestContent
|
||||
import com.habitrpg.android.habitica.models.inventory.*
|
||||
import com.habitrpg.android.habitica.models.responses.BuyResponse
|
||||
import com.habitrpg.android.habitica.models.responses.FeedResponse
|
||||
import com.habitrpg.android.habitica.models.shops.Shop
|
||||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
import com.habitrpg.android.habitica.models.user.*
|
||||
|
||||
import io.reactivex.Flowable
|
||||
import io.realm.RealmResults
|
||||
|
||||
|
|
@ -34,6 +25,7 @@ interface InventoryRepository : ContentRepository {
|
|||
|
||||
fun getOwnedPets(): Flowable<RealmResults<OwnedPet>>
|
||||
fun getQuestContent(key: String): Flowable<QuestContent>
|
||||
fun getQuestContent(keys: List<String>): Flowable<RealmResults<QuestContent>>
|
||||
|
||||
fun getEquipment(searchedKeys: List<String>): Flowable<RealmResults<Equipment>>
|
||||
fun retrieveInAppRewards(): Flowable<List<ShopItem>>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
package com.habitrpg.android.habitica.data
|
||||
|
||||
import com.habitrpg.android.habitica.models.AchievementResult
|
||||
import com.habitrpg.android.habitica.models.Achievement
|
||||
import com.habitrpg.android.habitica.models.inventory.Quest
|
||||
import com.habitrpg.android.habitica.models.members.Member
|
||||
import com.habitrpg.android.habitica.models.responses.PostChatMessageResult
|
||||
import com.habitrpg.android.habitica.models.social.*
|
||||
import com.habitrpg.android.habitica.models.social.ChatMessage
|
||||
import com.habitrpg.android.habitica.models.social.FindUsernameResult
|
||||
import com.habitrpg.android.habitica.models.social.Group
|
||||
import com.habitrpg.android.habitica.models.social.GroupMembership
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.Single
|
||||
|
|
@ -75,7 +78,7 @@ interface SocialRepository : BaseRepository {
|
|||
|
||||
fun forceStartQuest(party: Group): Flowable<Quest>
|
||||
|
||||
fun getMemberAchievements(userId: String?): Flowable<AchievementResult>
|
||||
fun getMemberAchievements(userId: String?): Flowable<List<Achievement>>
|
||||
|
||||
fun getGroupMembership(id: String): Flowable<GroupMembership>
|
||||
fun getGroupMemberships(): Flowable<RealmResults<GroupMembership>>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.habitrpg.android.habitica.data
|
||||
|
||||
import com.habitrpg.android.habitica.models.Achievement
|
||||
import com.habitrpg.android.habitica.models.QuestAchievement
|
||||
import com.habitrpg.android.habitica.models.Skill
|
||||
import com.habitrpg.android.habitica.models.inventory.Customization
|
||||
import com.habitrpg.android.habitica.models.inventory.CustomizationSet
|
||||
|
|
@ -69,4 +71,7 @@ interface UserRepository : BaseRepository {
|
|||
|
||||
fun bulkAllocatePoints(user: User?, strength: Int, intelligence: Int, constitution: Int, perception: Int): Flowable<Stats>
|
||||
fun useCustomization(user: User?, type: String, category: String?, identifier: String): Flowable<User>
|
||||
fun retrieveAchievements(): Flowable<List<Achievement>>
|
||||
fun getAchievements(): Flowable<RealmResults<Achievement>>
|
||||
fun getQuestAchievements(): Flowable<RealmResults<QuestAchievement>>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -589,7 +589,7 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
return apiService.getMemberWithUsername(username).compose(configureApiCallObserver())
|
||||
}
|
||||
|
||||
override fun getMemberAchievements(memberId: String): Flowable<AchievementResult> {
|
||||
override fun getMemberAchievements(memberId: String): Flowable<List<Achievement>> {
|
||||
return apiService.getMemberAchievements(memberId).compose(configureApiCallObserver())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,13 @@ import com.habitrpg.android.habitica.models.shops.Shop
|
|||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
import com.habitrpg.android.habitica.models.user.*
|
||||
import io.reactivex.Flowable
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmResults
|
||||
|
||||
class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClient: ApiClient, userID: String, var appConfigManager: AppConfigManager) : ContentRepositoryImpl<InventoryLocalRepository>(localRepository, apiClient, userID), InventoryRepository {
|
||||
override fun getQuestContent(keys: List<String>): Flowable<RealmResults<QuestContent>> {
|
||||
return localRepository.getQuestContent(keys)
|
||||
}
|
||||
|
||||
override fun getQuestContent(key: String): Flowable<QuestContent> {
|
||||
return localRepository.getQuestContent(key)
|
||||
|
|
|
|||
|
|
@ -5,11 +5,14 @@ import com.habitrpg.android.habitica.data.SocialRepository
|
|||
import com.habitrpg.android.habitica.data.local.SocialLocalRepository
|
||||
import com.habitrpg.android.habitica.extensions.notNull
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.models.AchievementResult
|
||||
import com.habitrpg.android.habitica.models.Achievement
|
||||
import com.habitrpg.android.habitica.models.inventory.Quest
|
||||
import com.habitrpg.android.habitica.models.members.Member
|
||||
import com.habitrpg.android.habitica.models.responses.PostChatMessageResult
|
||||
import com.habitrpg.android.habitica.models.social.*
|
||||
import com.habitrpg.android.habitica.models.social.ChatMessage
|
||||
import com.habitrpg.android.habitica.models.social.FindUsernameResult
|
||||
import com.habitrpg.android.habitica.models.social.Group
|
||||
import com.habitrpg.android.habitica.models.social.GroupMembership
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.Single
|
||||
|
|
@ -284,7 +287,7 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
.doOnNext { localRepository.setQuestActivity(party, true) }
|
||||
}
|
||||
|
||||
override fun getMemberAchievements(userId: String?): Flowable<AchievementResult> {
|
||||
override fun getMemberAchievements(userId: String?): Flowable<List<Achievement>> {
|
||||
return if (userId == null) {
|
||||
Flowable.empty()
|
||||
} else apiClient.getMemberAchievements(userId)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import com.habitrpg.android.habitica.data.UserRepository
|
|||
import com.habitrpg.android.habitica.data.local.UserLocalRepository
|
||||
import com.habitrpg.android.habitica.helpers.AppConfigManager
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.models.Achievement
|
||||
import com.habitrpg.android.habitica.models.QuestAchievement
|
||||
import com.habitrpg.android.habitica.models.Skill
|
||||
import com.habitrpg.android.habitica.models.inventory.Customization
|
||||
import com.habitrpg.android.habitica.models.inventory.CustomizationSet
|
||||
|
|
@ -303,6 +305,20 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
return updateUser(user, updatePath, identifier)
|
||||
}
|
||||
|
||||
override fun retrieveAchievements(): Flowable<List<Achievement>> {
|
||||
return apiClient.getMemberAchievements(userID).doOnNext {
|
||||
localRepository.save(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAchievements(): Flowable<RealmResults<Achievement>> {
|
||||
return localRepository.getAchievements()
|
||||
}
|
||||
|
||||
override fun getQuestAchievements(): Flowable<RealmResults<QuestAchievement>> {
|
||||
return localRepository.getQuestAchievements(userID)
|
||||
}
|
||||
|
||||
private fun mergeUser(oldUser: User?, newUser: User): User {
|
||||
if (oldUser == null || !oldUser.isValid) {
|
||||
return oldUser ?: newUser
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ interface InventoryLocalRepository : ContentLocalRepository {
|
|||
|
||||
fun getInAppRewards(): Flowable<RealmResults<ShopItem>>
|
||||
fun getQuestContent(key: String): Flowable<QuestContent>
|
||||
fun getQuestContent(keys: List<String>): Flowable<RealmResults<QuestContent>>
|
||||
|
||||
fun getEquipment(searchedKeys: List<String>): Flowable<RealmResults<Equipment>>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.habitrpg.android.habitica.data.local
|
||||
|
||||
import com.habitrpg.android.habitica.models.Achievement
|
||||
import com.habitrpg.android.habitica.models.QuestAchievement
|
||||
import com.habitrpg.android.habitica.models.Skill
|
||||
import com.habitrpg.android.habitica.models.TutorialStep
|
||||
import com.habitrpg.android.habitica.models.social.ChatMessage
|
||||
|
|
@ -20,4 +22,6 @@ interface UserLocalRepository : BaseLocalRepository {
|
|||
fun getSkills(user: User): Flowable<RealmResults<Skill>>
|
||||
|
||||
fun getSpecialItems(user: User): Flowable<RealmResults<Skill>>
|
||||
fun getAchievements(): Flowable<RealmResults<Achievement>>
|
||||
fun getQuestAchievements(userID: String): Flowable<RealmResults<QuestAchievement>>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,13 @@ import io.realm.Sort
|
|||
|
||||
|
||||
class RealmInventoryLocalRepository(realm: Realm, private val context: Context) : RealmContentLocalRepository(realm), InventoryLocalRepository {
|
||||
override fun getQuestContent(keys: List<String>): Flowable<RealmResults<QuestContent>> {
|
||||
return realm.where(QuestContent::class.java)
|
||||
.`in`("key", keys.toTypedArray())
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
}
|
||||
|
||||
override fun getQuestContent(key: String): Flowable<QuestContent> {
|
||||
return realm.where(QuestContent::class.java).equalTo("key", key)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package com.habitrpg.android.habitica.data.local.implementation
|
||||
|
||||
import com.habitrpg.android.habitica.data.local.UserLocalRepository
|
||||
import com.habitrpg.android.habitica.models.Skill
|
||||
import com.habitrpg.android.habitica.models.Tag
|
||||
import com.habitrpg.android.habitica.models.TutorialStep
|
||||
import com.habitrpg.android.habitica.models.*
|
||||
import com.habitrpg.android.habitica.models.social.ChallengeMembership
|
||||
import com.habitrpg.android.habitica.models.social.ChatMessage
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
|
|
@ -12,6 +10,21 @@ import io.realm.Realm
|
|||
import io.realm.RealmResults
|
||||
|
||||
class RealmUserLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), UserLocalRepository {
|
||||
override fun getAchievements(): Flowable<RealmResults<Achievement>> {
|
||||
return realm.where(Achievement::class.java)
|
||||
.sort("index")
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
}
|
||||
|
||||
override fun getQuestAchievements(userID: String): Flowable<RealmResults<QuestAchievement>> {
|
||||
return realm.where(QuestAchievement::class.java)
|
||||
.equalTo("userID", userID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
}
|
||||
|
||||
override fun getTutorialSteps(): Flowable<RealmResults<TutorialStep>> = realm.where(TutorialStep::class.java).findAll().asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
package com.habitrpg.android.habitica.models;
|
||||
|
||||
public class Achievement {
|
||||
public String type;
|
||||
public String title;
|
||||
public String text;
|
||||
public String icon;
|
||||
public String category;
|
||||
public String key;
|
||||
public String value;
|
||||
public boolean earned;
|
||||
public int index;
|
||||
public Integer optionalCount;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.habitrpg.android.habitica.models
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
open class Achievement : RealmObject() {
|
||||
@PrimaryKey
|
||||
var key: String? = null
|
||||
var type: String? = null
|
||||
var title: String? = null
|
||||
var text: String? = null
|
||||
var icon: String? = null
|
||||
var category: String? = null
|
||||
var earned: Boolean = false
|
||||
var index: Int = 0
|
||||
var optionalCount: Int? = null
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.habitrpg.android.habitica.models
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Ignore
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
open class QuestAchievement: RealmObject() {
|
||||
@PrimaryKey
|
||||
var combinedKey: String? = null
|
||||
|
||||
var questKey: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
combinedKey = userID + questKey
|
||||
}
|
||||
var userID: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
combinedKey = userID + questKey
|
||||
}
|
||||
var count: Int = 0
|
||||
|
||||
@Ignore
|
||||
var title: String? = null
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.habitrpg.android.habitica.models.user
|
|||
import com.google.gson.annotations.SerializedName
|
||||
import com.habitrpg.android.habitica.models.Avatar
|
||||
import com.habitrpg.android.habitica.models.PushDevice
|
||||
import com.habitrpg.android.habitica.models.QuestAchievement
|
||||
import com.habitrpg.android.habitica.models.Tag
|
||||
import com.habitrpg.android.habitica.models.invitations.Invitations
|
||||
import com.habitrpg.android.habitica.models.social.ChallengeMembership
|
||||
|
|
@ -118,6 +119,11 @@ open class User : RealmObject(), Avatar {
|
|||
}
|
||||
|
||||
var tags = RealmList<Tag>()
|
||||
var questAchievements = RealmList<QuestAchievement>()
|
||||
set(value) {
|
||||
field = value
|
||||
field.forEach { it.userID = id }
|
||||
}
|
||||
|
||||
@Ignore
|
||||
var pushDevices: List<PushDevice>? = null
|
||||
|
|
|
|||
|
|
@ -20,15 +20,14 @@ import com.habitrpg.android.habitica.extensions.notNull
|
|||
import com.habitrpg.android.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.helpers.UserStatComputer
|
||||
import com.habitrpg.android.habitica.models.AchievementGroup
|
||||
import com.habitrpg.android.habitica.models.AchievementResult
|
||||
import com.habitrpg.android.habitica.models.Achievement
|
||||
import com.habitrpg.android.habitica.models.inventory.Equipment
|
||||
import com.habitrpg.android.habitica.models.members.Member
|
||||
import com.habitrpg.android.habitica.models.user.Outfit
|
||||
import com.habitrpg.android.habitica.models.user.Stats
|
||||
import com.habitrpg.android.habitica.ui.AvatarView
|
||||
import com.habitrpg.android.habitica.ui.AvatarWithBarsViewModel
|
||||
import com.habitrpg.android.habitica.ui.adapter.social.AchievementAdapter
|
||||
import com.habitrpg.android.habitica.ui.adapter.social.AchievementProfileAdapter
|
||||
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
|
||||
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser
|
||||
import com.habitrpg.android.habitica.ui.helpers.bindView
|
||||
|
|
@ -208,7 +207,7 @@ class FullProfileActivity : BaseActivity() {
|
|||
|
||||
|
||||
// Load the members achievements now
|
||||
compositeSubscription.add(socialRepository.getMemberAchievements(this.userID).subscribe(Consumer<AchievementResult> { this.fillAchievements(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(socialRepository.getMemberAchievements(this.userID).subscribe(Consumer { this.fillAchievements(it) }, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
|
||||
private fun updatePetsMountsView(user: Member) {
|
||||
|
|
@ -223,17 +222,17 @@ class FullProfileActivity : BaseActivity() {
|
|||
|
||||
// region Attributes
|
||||
|
||||
private fun fillAchievements(achievements: AchievementResult?) {
|
||||
private fun fillAchievements(achievements: List<Achievement>?) {
|
||||
if (achievements == null) {
|
||||
return
|
||||
}
|
||||
val items = ArrayList<Any>()
|
||||
|
||||
fillAchievements(achievements.basic, items)
|
||||
fillAchievements(achievements.seasonal, items)
|
||||
fillAchievements(achievements.special, items)
|
||||
fillAchievements(R.string.basic_achievements, achievements.filter { it.category == "basic" }, items)
|
||||
fillAchievements(R.string.seasonal_achievements, achievements.filter { it.category == "seasonal" }, items)
|
||||
fillAchievements(R.string.special_achievements, achievements.filter { it.category == "special" }, items)
|
||||
|
||||
val adapter = AchievementAdapter()
|
||||
val adapter = AchievementProfileAdapter()
|
||||
adapter.setItemList(items)
|
||||
|
||||
val layoutManager = androidx.recyclerview.widget.GridLayoutManager(this, 3)
|
||||
|
|
@ -252,12 +251,12 @@ class FullProfileActivity : BaseActivity() {
|
|||
stopAndHideProgress(achievementProgress)
|
||||
}
|
||||
|
||||
private fun fillAchievements(achievementGroup: AchievementGroup, targetList: MutableList<Any>) {
|
||||
private fun fillAchievements(labelID: Int, achievements: List<Achievement>, targetList: MutableList<Any>) {
|
||||
// Order by ID first
|
||||
val achievementList = ArrayList(achievementGroup.achievements.values)
|
||||
val achievementList = ArrayList(achievements)
|
||||
achievementList.sortWith(Comparator { achievement, t1 -> java.lang.Double.compare(achievement.index.toDouble(), t1.index.toDouble()) })
|
||||
|
||||
targetList.add(achievementGroup.label)
|
||||
targetList.add(getString(labelID))
|
||||
targetList.addAll(achievementList)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
package com.habitrpg.android.habitica.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.extensions.inflate
|
||||
import com.habitrpg.android.habitica.models.Achievement
|
||||
import com.habitrpg.android.habitica.models.QuestAchievement
|
||||
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
|
||||
import com.habitrpg.android.habitica.ui.helpers.bindOptionalView
|
||||
import com.habitrpg.android.habitica.ui.helpers.bindView
|
||||
|
||||
class AchievementsAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
var useGridLayout: Boolean = false
|
||||
var entries = listOf<Any>()
|
||||
var questAchievements = listOf<QuestAchievement>()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
0 -> SectionViewHolder(parent.inflate(R.layout.achievement_section_header))
|
||||
3 -> QuestAchievementViewHolder(parent.inflate(R.layout.achievement_quest_item))
|
||||
else -> AchievementViewHolder(if (useGridLayout) {
|
||||
parent.inflate(R.layout.achievement_grid_item)
|
||||
} else {
|
||||
parent.inflate(R.layout.achievement_list_item)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when {
|
||||
entries.size > position -> when (val entry = entries[position]) {
|
||||
is Achievement -> (holder as? AchievementViewHolder)?.bind(entry)
|
||||
is Pair<*, *> -> (holder as? SectionViewHolder)?.bind(entry)
|
||||
}
|
||||
entries.size == position -> (holder as? SectionViewHolder)?.bind(Pair("Quests completed", questAchievements.size))
|
||||
else -> (holder as? QuestAchievementViewHolder)?.bind(questAchievements[position - 1 - entries.size])
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return entries.size + questAchievements.size + 1
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return when {
|
||||
entries.size > position -> {
|
||||
val entry = entries[position]
|
||||
if (entry is Pair<*, *>) {
|
||||
0
|
||||
} else {
|
||||
if (useGridLayout) 1 else 2
|
||||
}
|
||||
}
|
||||
entries.size == position -> 0
|
||||
else -> 3
|
||||
}
|
||||
}
|
||||
|
||||
class SectionViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
|
||||
private val titleView: TextView by bindView(R.id.title)
|
||||
private val countView: TextView by bindView(R.id.count_label)
|
||||
|
||||
fun bind(category: Pair<*, *>) {
|
||||
titleView.text = category.first as? String
|
||||
countView.text = category.second.toString()
|
||||
}
|
||||
}
|
||||
|
||||
class AchievementViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
|
||||
private var achievement: Achievement? = null
|
||||
|
||||
private val achievementContainer: ViewGroup? by bindOptionalView(R.id.achievement_container)
|
||||
private val achievementIconView: SimpleDraweeView by bindView(R.id.achievement_icon)
|
||||
private val achievementCountView: TextView by bindView(R.id.achievement_count_label)
|
||||
private val achievementTitleView: TextView by bindView(R.id.achievement_title)
|
||||
private val achievementDescriptionView: TextView? by bindOptionalView(R.id.achievement_description)
|
||||
|
||||
fun bind(achievement: Achievement) {
|
||||
this.achievement = achievement
|
||||
val iconName = if (achievement.earned) {
|
||||
achievement.icon + "2x"
|
||||
} else {
|
||||
"achievement-unearned2x"
|
||||
}
|
||||
DataBindingUtils.loadImage(achievementIconView, iconName)
|
||||
achievementTitleView.text = achievement.title
|
||||
achievementDescriptionView?.text = achievement.text
|
||||
if (achievement.optionalCount ?: 0 > 0) {
|
||||
achievementCountView.visibility = View.VISIBLE
|
||||
achievementCountView.text = achievement.optionalCount.toString()
|
||||
} else {
|
||||
achievementCountView.visibility = View.GONE
|
||||
}
|
||||
achievementContainer?.clipToOutline = true
|
||||
}
|
||||
}
|
||||
|
||||
class QuestAchievementViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
|
||||
private var achievement: QuestAchievement? = null
|
||||
|
||||
private val achievementCountView: TextView by bindView(R.id.achievement_count_label)
|
||||
private val achievementTitleView: TextView by bindView(R.id.achievement_title)
|
||||
|
||||
fun bind(achievement: QuestAchievement) {
|
||||
this.achievement = achievement
|
||||
achievementTitleView.text = achievement.title
|
||||
achievementCountView.text = achievement.count.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ import com.habitrpg.android.habitica.ui.helpers.bindView
|
|||
import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog
|
||||
|
||||
class AchievementAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
class AchievementProfileAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
var itemType: String? = null
|
||||
var activity: MainActivity? = null
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
package com.habitrpg.android.habitica.ui.fragments
|
||||
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.AppComponent
|
||||
import com.habitrpg.android.habitica.data.InventoryRepository
|
||||
import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.models.Achievement
|
||||
import com.habitrpg.android.habitica.ui.adapter.AchievementsAdapter
|
||||
import com.habitrpg.android.habitica.ui.helpers.bindView
|
||||
import com.habitrpg.android.habitica.ui.helpers.resetViews
|
||||
import io.reactivex.functions.Action
|
||||
import io.reactivex.functions.Consumer
|
||||
import io.reactivex.rxkotlin.combineLatest
|
||||
import io.realm.RealmResults
|
||||
import javax.inject.Inject
|
||||
|
||||
class AchievementsFragment: BaseMainFragment(), SwipeRefreshLayout.OnRefreshListener {
|
||||
|
||||
@Inject
|
||||
lateinit var inventoryRepository: InventoryRepository
|
||||
|
||||
private var menuID: Int = 0
|
||||
private lateinit var adapter: AchievementsAdapter
|
||||
private val layoutManager = GridLayoutManager(activity, 2)
|
||||
private var useGridLayout = true
|
||||
set(value) {
|
||||
field = value
|
||||
adapter.useGridLayout = value
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private val recyclerView: RecyclerView by bindView(R.id.recyclerView)
|
||||
private val refreshLayout: SwipeRefreshLayout by bindView(R.id.refreshLayout)
|
||||
|
||||
override fun injectFragment(component: AppComponent) {
|
||||
component.inject(this)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
hidesToolbar = true
|
||||
super.onCreateView(inflater, container, savedInstanceState)
|
||||
adapter = AchievementsAdapter()
|
||||
return inflater.inflate(R.layout.fragment_refresh_recyclerview, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
resetViews()
|
||||
|
||||
recyclerView.layoutManager = layoutManager
|
||||
recyclerView.adapter = adapter
|
||||
adapter.useGridLayout = useGridLayout
|
||||
context?.let { recyclerView.background = ColorDrawable(ContextCompat.getColor(it, R.color.white)) }
|
||||
|
||||
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
return if (adapter.getItemViewType(position) == 1) {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
refreshLayout.setOnRefreshListener(this)
|
||||
|
||||
compositeSubscription.add(userRepository.getAchievements().subscribe(Consumer<RealmResults<Achievement>> {
|
||||
val entries = mutableListOf<Any>()
|
||||
var lastCategory = ""
|
||||
it.forEach { achievement ->
|
||||
val categoryIdentifier = achievement.category ?: ""
|
||||
if (categoryIdentifier != lastCategory) {
|
||||
val category = Pair(categoryIdentifier, it.count { check ->
|
||||
check.category == categoryIdentifier && check.earned
|
||||
})
|
||||
entries.add(category)
|
||||
lastCategory = categoryIdentifier
|
||||
}
|
||||
entries.add(achievement)
|
||||
}
|
||||
adapter.entries = entries
|
||||
adapter.notifyDataSetChanged()
|
||||
}, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(userRepository.getQuestAchievements()
|
||||
.combineLatest(userRepository.getQuestAchievements()
|
||||
.map { it.mapNotNull { achievement -> achievement.questKey } }
|
||||
.flatMap { inventoryRepository.getQuestContent(it) })
|
||||
.subscribeWithErrorHandler(Consumer { result ->
|
||||
val achievements = result.first.map {achievement ->
|
||||
val questContent = result.second.firstOrNull { achievement.questKey == it.key }
|
||||
achievement.title = questContent?.text
|
||||
achievement
|
||||
}
|
||||
adapter.questAchievements = achievements
|
||||
adapter.notifyDataSetChanged()
|
||||
}))
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
||||
if (useGridLayout) {
|
||||
val menuItem = menu?.add(R.string.switch_to_list_view)
|
||||
menuID = menuItem?.itemId ?: 0
|
||||
menuItem?.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
|
||||
menuItem?.setIcon(R.drawable.ic_round_view_list_24px)
|
||||
|
||||
} else {
|
||||
val menuItem = menu?.add(R.string.switch_to_grid_view)
|
||||
menuID = menuItem?.itemId ?: 0
|
||||
menuItem?.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
|
||||
menuItem?.setIcon(R.drawable.ic_round_view_module_24px)
|
||||
}
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
if (item?.itemId == menuID) {
|
||||
useGridLayout = !useGridLayout
|
||||
activity?.invalidateOptionsMenu()
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onRefresh() {
|
||||
compositeSubscription.add(userRepository.retrieveAchievements().subscribe(Consumer {
|
||||
}, RxErrorHandler.handleEmptyError(), Action { refreshLayout.isRefreshing = false }))
|
||||
}
|
||||
}
|
||||
|
|
@ -208,6 +208,7 @@ class NavigationDrawerFragment : DialogFragment() {
|
|||
items.add(HabiticaDrawerItem(R.id.tasksFragment, SIDEBAR_TASKS, context.getString(R.string.sidebar_tasks)))
|
||||
items.add(HabiticaDrawerItem(R.id.skillsFragment, SIDEBAR_SKILLS, context.getString(R.string.sidebar_skills)))
|
||||
items.add(HabiticaDrawerItem(R.id.statsFragment, SIDEBAR_STATS, context.getString(R.string.sidebar_stats)))
|
||||
items.add(HabiticaDrawerItem(R.id.achievementsFragment, SIDEBAR_ACHIEVEMENTS, context.getString(R.string.sidebar_achievements)))
|
||||
items.add(HabiticaDrawerItem(0, SIDEBAR_SOCIAL, context.getString(R.string.sidebar_section_social), true))
|
||||
items.add(HabiticaDrawerItem(R.id.tavernFragment, SIDEBAR_TAVERN, context.getString(R.string.sidebar_tavern), false, false))
|
||||
items.add(HabiticaDrawerItem(R.id.partyFragment, SIDEBAR_PARTY, context.getString(R.string.sidebar_party)))
|
||||
|
|
@ -327,6 +328,7 @@ class NavigationDrawerFragment : DialogFragment() {
|
|||
const val SIDEBAR_TASKS = "tasks"
|
||||
const val SIDEBAR_SKILLS = "skills"
|
||||
const val SIDEBAR_STATS = "stats"
|
||||
const val SIDEBAR_ACHIEVEMENTS = "achievements"
|
||||
const val SIDEBAR_SOCIAL = "social"
|
||||
const val SIDEBAR_INBOX = "inbox"
|
||||
const val SIDEBAR_TAVERN = "tavern"
|
||||
|
|
|
|||
|
|
@ -232,15 +232,17 @@ class QuestDetailFragment : BaseMainFragment() {
|
|||
}
|
||||
|
||||
private fun onQuestBegin() {
|
||||
context?.let {
|
||||
val alert = HabiticaAlertDialog(it)
|
||||
val context = context
|
||||
if (context != null) {
|
||||
val alert = HabiticaAlertDialog(context)
|
||||
alert.setMessage(beginQuestMessage)
|
||||
alert.addButton(R.string.yes, true) { _, _ ->
|
||||
party.notNull { party ->
|
||||
socialRepository.forceStartQuest(party)
|
||||
.subscribe(Consumer { }, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
}
|
||||
val party = party
|
||||
if (party != null) {
|
||||
socialRepository.forceStartQuest(party)
|
||||
.subscribe(Consumer { }, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
}
|
||||
alert.addButton(R.string.no, false)
|
||||
alert.show()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,8 +183,9 @@ class PartyDetailFragment : BaseFragment() {
|
|||
}
|
||||
|
||||
private fun leaveParty() {
|
||||
activity?.let {
|
||||
val alert = HabiticaAlertDialog(it)
|
||||
val context = context
|
||||
if (context != null) {
|
||||
val alert = HabiticaAlertDialog(context)
|
||||
alert.setMessage(R.string.leave_party_confirmation)
|
||||
alert.addButton(R.string.yes, true) { _, _ ->
|
||||
viewModel?.leaveGroup { }
|
||||
|
|
|
|||
|
|
@ -166,7 +166,9 @@ open class HabiticaAlertDialog(context: Context) : AlertDialog(context, R.style.
|
|||
val buttonIndex = buttonsWrapper.childCount
|
||||
buttonView.setOnClickListener {
|
||||
weakThis.get()?.let { it1 ->
|
||||
function?.invoke(it1, buttonIndex)
|
||||
if (function != null) {
|
||||
function(it1, buttonIndex)
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package com.habitrpg.android.habitica.utils
|
||||
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.habitrpg.android.habitica.extensions.getAsString
|
||||
import com.habitrpg.android.habitica.models.Achievement
|
||||
import java.lang.reflect.Type
|
||||
|
||||
class AchievementListDeserializer: JsonDeserializer<List<Achievement>> {
|
||||
|
||||
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): List<Achievement> {
|
||||
val achievements = mutableListOf<Achievement>()
|
||||
for (categoryEntry in json?.asJsonObject?.entrySet() ?: emptySet()) {
|
||||
val categoryIdentifier = categoryEntry.key
|
||||
for (entry in categoryEntry.value.asJsonObject.getAsJsonObject("achievements").entrySet()) {
|
||||
var obj = entry.value.asJsonObject
|
||||
val achievement = Achievement()
|
||||
achievement.key = entry.key
|
||||
achievement.category = categoryIdentifier
|
||||
achievement.earned = obj.get("earned").asBoolean
|
||||
achievement.title = obj.getAsString("title")
|
||||
achievement.text = obj.getAsString("text")
|
||||
achievement.icon = obj.getAsString("icon")
|
||||
achievement.index = if (obj.has("index")) obj["index"].asInt else 0
|
||||
achievement.optionalCount = if (obj.has("optionalCount")) obj["optionalCount"].asInt else 0
|
||||
achievements.add(achievement)
|
||||
}
|
||||
}
|
||||
return achievements
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.habitrpg.android.habitica.utils
|
||||
|
||||
import android.os.Trace
|
||||
import com.google.firebase.perf.FirebasePerformance
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
|
|
@ -8,6 +7,7 @@ import com.google.gson.JsonElement
|
|||
import com.google.gson.JsonParseException
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.habitrpg.android.habitica.models.PushDevice
|
||||
import com.habitrpg.android.habitica.models.QuestAchievement
|
||||
import com.habitrpg.android.habitica.models.Tag
|
||||
import com.habitrpg.android.habitica.models.inventory.Quest
|
||||
import com.habitrpg.android.habitica.models.invitations.Invitations
|
||||
|
|
@ -118,12 +118,22 @@ class UserDeserializer : JsonDeserializer<User> {
|
|||
}
|
||||
|
||||
if (obj.has("achievements")) {
|
||||
if (obj.getAsJsonObject("achievements").has("streak")) {
|
||||
val achievements = obj.getAsJsonObject("achievements")
|
||||
if (achievements.has("streak")) {
|
||||
try {
|
||||
user.streakCount = obj.getAsJsonObject("achievements").get("streak").asInt
|
||||
} catch (ignored: UnsupportedOperationException) {
|
||||
}
|
||||
|
||||
}
|
||||
if (achievements.has("quests")) {
|
||||
val questAchievements = RealmList<QuestAchievement>()
|
||||
for (entry in achievements.getAsJsonObject("quests").entrySet()) {
|
||||
val questAchievement = QuestAchievement()
|
||||
questAchievement.questKey = entry.key
|
||||
questAchievement.count = entry.value.asInt
|
||||
questAchievements.add(questAchievement)
|
||||
}
|
||||
user.questAchievements = questAchievements
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue