mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-04-14 19:56:32 +00:00
improve party view
This commit is contained in:
parent
44d1673f7d
commit
cc79b47fb3
19 changed files with 628 additions and 79 deletions
|
|
@ -2,8 +2,8 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.habitrpg.android.habitica"
|
||||
android:versionCode="1916"
|
||||
android:versionName="1.1.3"
|
||||
android:versionCode="1917"
|
||||
android:versionName="1.1.4"
|
||||
android:screenOrientation="portrait"
|
||||
android:installLocation="auto" >
|
||||
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/CardView.Default"
|
||||
android:id="@+id/party_invitation_wrapper"
|
||||
>
|
||||
|
||||
android:id="@+id/party_invitation_wrapper">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -119,8 +117,7 @@
|
|||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_keyboard_arrow_right_gray_24dp"
|
||||
android:visibility="gone"/>
|
||||
app:srcCompat="@drawable/ic_keyboard_arrow_right_gray_24dp"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/quest_image_wrapper"
|
||||
|
|
|
|||
160
Habitica/res/layout/fragment_quest_detail.xml
Normal file
160
Habitica/res/layout/fragment_quest_detail.xml
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v4.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="?attr/actionBarSize">
|
||||
<LinearLayout
|
||||
android:background="@color/white"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="@dimen/content_border"
|
||||
android:paddingRight="@dimen/content_border"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
>
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/quest_scroll_image_view"
|
||||
android:layout_width="63dp"
|
||||
android:layout_height="63dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:padding="6dp"
|
||||
android:background="@color/gray_700"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_vertical">
|
||||
<TextView
|
||||
android:id="@+id/quest_title_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Headline"
|
||||
tools:text="Vice, Part 3: Vice Awakens"
|
||||
android:textStyle="bold"/>
|
||||
<TextView
|
||||
android:id="@+id/quest_leader_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Subheader2"
|
||||
tools:text="Started by Username"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/black_10_alpha"/>
|
||||
<LinearLayout
|
||||
android:background="@color/white"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingLeft="@dimen/content_border"
|
||||
android:paddingRight="@dimen/content_border"
|
||||
android:paddingBottom="12dp">
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/description"
|
||||
style="@style/Body1"
|
||||
android:layout_marginBottom="6dp"/>
|
||||
<TextView
|
||||
android:id="@+id/description_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Body2"
|
||||
tools:text="This is the description"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/content_section_spacing"
|
||||
android:layout_marginBottom="@dimen/header_spacing">
|
||||
<TextView
|
||||
android:id="@+id/participants_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Participants"
|
||||
style="@style/Body1"/>
|
||||
<TextView
|
||||
android:id="@+id/participants_header_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Body1"
|
||||
tools:text="3"
|
||||
android:textColor="@color/gray_300"
|
||||
android:layout_marginLeft="6dp"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/quest_participant_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
</LinearLayout>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/black_10_alpha"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/quest_participant_response_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
android:padding="@dimen/content_border">
|
||||
|
||||
<Button
|
||||
android:id="@+id/quest_accept_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/quest.accept"
|
||||
style="@style/HabiticaButton.Green"
|
||||
android:layout_marginRight="16dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/quest_reject_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/quest.reject"
|
||||
style="@style/HabiticaButton.Red"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/quest_leader_response_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
android:padding="@dimen/content_border">
|
||||
<Button
|
||||
android:id="@+id/quest_begin_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/quest.begin"
|
||||
style="@style/HabiticaButton.Yellow"
|
||||
android:layout_marginRight="16dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/quest_cancel_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/quest.cancel"
|
||||
style="@style/HabiticaButton.Red" />
|
||||
<Button
|
||||
android:id="@+id/quest_abort_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/quest.abort"
|
||||
style="@style/HabiticaButton.Red" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</android.support.v4.widget.NestedScrollView>
|
||||
26
Habitica/res/layout/quest_participant.xml
Normal file
26
Habitica/res/layout/quest_participant.xml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="6dp">
|
||||
<ImageView
|
||||
android:id="@+id/avatar_view"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:scaleType="fitCenter"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/participant_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"/>
|
||||
<TextView
|
||||
android:id="@+id/status_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -107,4 +107,7 @@
|
|||
<dimen name="setup_customization_size">56dp</dimen>
|
||||
<dimen name="outer_inset">16dp</dimen>
|
||||
<dimen name="rounded_button_radius">6dp</dimen>
|
||||
<dimen name="content_border">21dp</dimen>
|
||||
<dimen name="content_section_spacing">21dp</dimen>
|
||||
<dimen name="header_spacing">6dp</dimen>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -615,4 +615,11 @@
|
|||
<string name="start_day">Start My Day</string>
|
||||
<string name="leave_party_confirmation">Are you sure you want to leave the Party?</string>
|
||||
<string name="nextPrizeUnlocksIn" formatted="false">Next Prize in %d Check-ins</string>
|
||||
<string name="pending">Pending</string>
|
||||
<string name="accepted">Accepted</string>
|
||||
<string name="declined">Declined</string>
|
||||
<string name="participants">Participants</string>
|
||||
<string name="invitations">Invitations</string>
|
||||
<string name="quest_leader_header" formatted="false">Started by %s</string>
|
||||
<string name="quest_abort_message">Are you sure you want to abort this mission? It will abort it for everyone in your party and all progress will be lost. The quest scroll will be returned to the quest owner.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ import com.habitrpg.android.habitica.ui.fragments.social.GuildsOverviewFragment;
|
|||
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.QuestDetailFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.TavernDetailFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.TavernFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.challenges.ChallengeDetailDialogHolder;
|
||||
|
|
@ -271,4 +272,6 @@ public interface AppComponent {
|
|||
void inject(TavernDetailFragment tavernDetailFragment);
|
||||
|
||||
void inject(PartyDetailFragment partyDetailFragment);
|
||||
|
||||
void inject(QuestDetailFragment questDetailFragment);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl<SocialLocalReposito
|
|||
@Override
|
||||
public Observable<List<Member>> retrieveGroupMembers(String id, boolean includeAllPublicFields) {
|
||||
return apiClient.getGroupMembers(id, includeAllPublicFields)
|
||||
.doOnNext(localRepository::save);
|
||||
.doOnNext(members -> localRepository.saveGroupMembers(id, members));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -232,12 +232,14 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl<SocialLocalReposito
|
|||
|
||||
@Override
|
||||
public Observable<Void> cancelQuest(String partyId) {
|
||||
return apiClient.cancelQuest(partyId);
|
||||
return apiClient.cancelQuest(partyId)
|
||||
.doOnNext(aVoid -> localRepository.removeQuest(partyId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<Quest> abortQuest(String partyId) {
|
||||
return apiClient.abortQuest(partyId);
|
||||
return apiClient.abortQuest(partyId)
|
||||
.doOnNext(aVoid -> localRepository.removeQuest(partyId));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -247,6 +249,7 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl<SocialLocalReposito
|
|||
|
||||
@Override
|
||||
public Observable<Quest> forceStartQuest(Group party) {
|
||||
return apiClient.forceStartQuest(party.id, localRepository.getUnmanagedCopy(party));
|
||||
return apiClient.forceStartQuest(party.id, localRepository.getUnmanagedCopy(party))
|
||||
.doOnNext(aVoid -> localRepository.setQuestActivity(party, true));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,4 +29,10 @@ public interface SocialLocalRepository extends BaseLocalRepository {
|
|||
void updateRSVPNeeded(User user, boolean newValue);
|
||||
|
||||
void likeMessage(ChatMessage chatMessage, String userId, boolean liked);
|
||||
|
||||
void saveGroupMembers(String groupId, List<Member> members);
|
||||
|
||||
void removeQuest(String partyId);
|
||||
|
||||
void setQuestActivity(Group party, boolean active);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ import com.habitrpg.android.habitica.models.social.ChatMessageLike;
|
|||
import com.habitrpg.android.habitica.models.social.Group;
|
||||
import com.habitrpg.android.habitica.models.user.User;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.realm.Realm;
|
||||
import io.realm.RealmResults;
|
||||
import io.realm.Sort;
|
||||
|
|
@ -107,6 +110,53 @@ public class RealmSocialLocalRepository extends RealmBaseLocalRepository impleme
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveGroupMembers(String groupId, List<Member> members) {
|
||||
realm.executeTransaction(realm1 -> realm.insertOrUpdate(members));
|
||||
if (groupId != null) {
|
||||
List<Member> existingMembers = realm.where(Member.class).equalTo("party.id", groupId).findAll();
|
||||
List<Member> membersToRemove = new ArrayList<>();
|
||||
for (Member existingMember : existingMembers) {
|
||||
boolean isStillMember = false;
|
||||
for (Member newMember : members) {
|
||||
if (existingMember.getId() != null && existingMember.getId().equals(newMember.getId())) {
|
||||
isStillMember = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isStillMember) {
|
||||
membersToRemove.add(existingMember);
|
||||
}
|
||||
}
|
||||
realm.executeTransaction(realm1 -> {
|
||||
for (Member member : membersToRemove) {
|
||||
member.deleteFromRealm();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeQuest(String partyId) {
|
||||
Group party = realm.where(Group.class).equalTo("id", partyId).findFirst();
|
||||
if (party != null) {
|
||||
realm.executeTransaction(realm1 -> {
|
||||
party.quest = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuestActivity(Group party, boolean active) {
|
||||
realm.executeTransaction(realm1 -> {
|
||||
if (party != null && party.quest != null) {
|
||||
party.quest.active = active;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private Observable<ChatMessage> getMessage(String id) {
|
||||
return realm.where(ChatMessage.class).equalTo("id", id)
|
||||
.findAllAsync()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.habitrpg.android.habitica.models.inventory;
|
||||
|
||||
import com.habitrpg.android.habitica.models.members.Member;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import io.realm.RealmList;
|
||||
|
|
@ -18,6 +20,8 @@ public class Quest extends RealmObject {
|
|||
public RealmList<QuestMember> members;
|
||||
private QuestProgress progress;
|
||||
|
||||
public RealmList<Member> participants;
|
||||
|
||||
private Quest(String key, QuestProgress progress) {
|
||||
this.key = key;
|
||||
this.progress = progress;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ public class Member extends RealmObject implements Avatar {
|
|||
private String currentMount;
|
||||
private String currentPet;
|
||||
|
||||
private Boolean participatesInQuest;
|
||||
|
||||
public Preferences getPreferences() {
|
||||
return preferences;
|
||||
}
|
||||
|
|
@ -313,4 +315,19 @@ public class Member extends RealmObject implements Avatar {
|
|||
public boolean getSleep() {
|
||||
return getPreferences() != null && getPreferences().getSleep();
|
||||
}
|
||||
|
||||
public Boolean getParticipatesInQuest() {
|
||||
return participatesInQuest;
|
||||
}
|
||||
|
||||
public void setParticipatesInQuest(Boolean participatesInQuest) {
|
||||
this.participatesInQuest = participatesInQuest;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
if (profile == null) {
|
||||
return "";
|
||||
}
|
||||
return profile.getName();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.models.social;
|
|||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.habitrpg.android.habitica.models.inventory.Quest;
|
||||
import com.habitrpg.android.habitica.models.members.Member;
|
||||
import com.habitrpg.android.habitica.models.user.User;
|
||||
|
||||
import io.realm.RealmList;
|
||||
|
|
@ -44,7 +45,6 @@ public class Group extends RealmObject {
|
|||
|
||||
public String leaderMessage;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ import rx.subjects.PublishSubject;
|
|||
|
||||
public class ItemRecyclerAdapter extends RealmRecyclerViewAdapter<Item, ItemRecyclerAdapter.ItemViewHolder> {
|
||||
|
||||
public Boolean isHatching;
|
||||
public Boolean isFeeding;
|
||||
public boolean isHatching;
|
||||
public boolean isFeeding;
|
||||
public Item hatchingItem;
|
||||
public Pet feedingPet;
|
||||
public ItemRecyclerFragment fragment;
|
||||
|
|
@ -135,7 +135,7 @@ public class ItemRecyclerAdapter extends RealmRecyclerViewAdapter<Item, ItemRecy
|
|||
}
|
||||
imageName = "Pet_" + type + "_" + item.getKey();
|
||||
|
||||
if (isHatching != null && isHatching) {
|
||||
if (isHatching) {
|
||||
disabled = this.isPetOwned();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ public class ItemRecyclerFragment extends BaseFragment {
|
|||
public ItemRecyclerAdapter adapter;
|
||||
public String itemType;
|
||||
public String itemTypeText;
|
||||
public Boolean isHatching;
|
||||
public Boolean isFeeding;
|
||||
public boolean isHatching;
|
||||
public boolean isFeeding;
|
||||
public Item hatchingItem;
|
||||
public Pet feedingPet;
|
||||
@Nullable
|
||||
|
|
@ -118,14 +118,14 @@ public class ItemRecyclerFragment extends BaseFragment {
|
|||
this.itemType = savedInstanceState.getString(ITEM_TYPE_KEY, "");
|
||||
}
|
||||
|
||||
if (this.isHatching != null && this.isHatching) {
|
||||
if (this.isHatching) {
|
||||
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
this.titleView.setText(getString(R.string.hatch_with, this.hatchingItem.getText()));
|
||||
this.titleView.setVisibility(View.VISIBLE);
|
||||
this.footerView.setText(getString(R.string.hatching_market_info));
|
||||
this.footerView.setVisibility(View.VISIBLE);
|
||||
this.openMarketButton.setVisibility(View.VISIBLE);
|
||||
} else if (this.isFeeding != null && this.isFeeding) {
|
||||
} else if (this.isFeeding) {
|
||||
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
this.titleView.setText(getString(R.string.dialog_feeding, this.feedingPet.getColorText(), this.feedingPet.getAnimalText()));
|
||||
this.titleView.setVisibility(View.VISIBLE);
|
||||
|
|
@ -160,7 +160,7 @@ public class ItemRecyclerFragment extends BaseFragment {
|
|||
|
||||
@Override
|
||||
public void onResume() {
|
||||
if (((this.isHatching != null && this.isHatching) || (this.isFeeding != null && this.isFeeding)) && getDialog().getWindow() != null) {
|
||||
if ((this.isHatching || this.isFeeding) && getDialog().getWindow() != null) {
|
||||
android.view.WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
|
||||
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
params.verticalMargin = 60;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,261 @@
|
|||
package com.habitrpg.android.habitica.ui.fragments.social;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.widget.TextViewCompat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
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.data.SocialRepository;
|
||||
import com.habitrpg.android.habitica.data.UserRepository;
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler;
|
||||
import com.habitrpg.android.habitica.models.inventory.Quest;
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestContent;
|
||||
import com.habitrpg.android.habitica.models.members.Member;
|
||||
import com.habitrpg.android.habitica.models.social.Group;
|
||||
import com.habitrpg.android.habitica.models.user.User;
|
||||
import com.habitrpg.android.habitica.modules.AppModule;
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment;
|
||||
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils;
|
||||
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.OnClick;
|
||||
|
||||
public class QuestDetailFragment extends BaseMainFragment {
|
||||
|
||||
@Inject
|
||||
SocialRepository socialRepository;
|
||||
@Inject
|
||||
UserRepository userRepository;
|
||||
@Inject
|
||||
InventoryRepository inventoryRepository;
|
||||
@Inject
|
||||
@Named(AppModule.NAMED_USER_ID)
|
||||
String userId;
|
||||
|
||||
@BindView(R.id.quest_title_view)
|
||||
TextView questTitleView;
|
||||
@BindView(R.id.quest_scroll_image_view)
|
||||
SimpleDraweeView questScrollImageView;
|
||||
@BindView(R.id.quest_leader_view)
|
||||
TextView questLeaderView;
|
||||
@BindView(R.id.description_view)
|
||||
TextView questDescriptionView;
|
||||
@BindView(R.id.quest_participant_list)
|
||||
LinearLayout questParticipantList;
|
||||
@BindView(R.id.participants_header)
|
||||
TextView participantHeader;
|
||||
@BindView(R.id.participants_header_count)
|
||||
TextView participantHeaderCount;
|
||||
@BindView(R.id.quest_participant_response_wrapper)
|
||||
ViewGroup questParticipantResponseWrapper;
|
||||
@BindView(R.id.quest_leader_response_wrapper)
|
||||
ViewGroup questLeaderResponseWrapper;
|
||||
@BindView(R.id.quest_accept_button)
|
||||
Button questAcceptButton;
|
||||
@BindView(R.id.quest_reject_button)
|
||||
Button questRejectButton;
|
||||
@BindView(R.id.quest_begin_button)
|
||||
Button questBeginButton;
|
||||
@BindView(R.id.quest_cancel_button)
|
||||
Button questCancelButton;
|
||||
@BindView(R.id.quest_abort_button)
|
||||
Button questAbortButton;
|
||||
|
||||
public String partyId;
|
||||
public String questKey;
|
||||
private Group party;
|
||||
private Quest quest;
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
return inflater.inflate(R.layout.fragment_quest_detail, container, false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
compositeSubscription.add(socialRepository.getGroup(partyId).subscribe(this::updateParty, RxErrorHandler.handleEmptyError()));
|
||||
compositeSubscription.add(inventoryRepository.getQuestContent(questKey).subscribe(this::updateQuestContent, RxErrorHandler.handleEmptyError()));
|
||||
}
|
||||
|
||||
|
||||
private void updateParty(Group group) {
|
||||
if (questTitleView == null || group.quest == null) {
|
||||
return;
|
||||
}
|
||||
party = group;
|
||||
quest = group.quest;
|
||||
setQuestParticipants(group.quest.participants);
|
||||
socialRepository.getMember(quest.leader).first().subscribe(member -> questLeaderView.setText(getContext().getString(R.string.quest_leader_header, member.getDisplayName())), RxErrorHandler.handleEmptyError());
|
||||
|
||||
if (questLeaderResponseWrapper != null) {
|
||||
if (showParticipatantButtons()) {
|
||||
questLeaderResponseWrapper.setVisibility(View.GONE);
|
||||
questParticipantResponseWrapper.setVisibility(View.VISIBLE);
|
||||
} else if (showLeaderButtons()) {
|
||||
questParticipantResponseWrapper.setVisibility(View.GONE);
|
||||
questLeaderResponseWrapper.setVisibility(View.VISIBLE);
|
||||
if (isQuestActive()) {
|
||||
questBeginButton.setVisibility(View.GONE);
|
||||
questCancelButton.setVisibility(View.GONE);
|
||||
questAbortButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
questBeginButton.setVisibility(View.VISIBLE);
|
||||
questCancelButton.setVisibility(View.VISIBLE);
|
||||
questAbortButton.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
questLeaderResponseWrapper.setVisibility(View.GONE);
|
||||
questParticipantResponseWrapper.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean showLeaderButtons() {
|
||||
return party != null && party.quest != null && userId != null && userId.equals(party.quest.leader);
|
||||
}
|
||||
|
||||
private boolean showParticipatantButtons() {
|
||||
if (user == null || user.getParty() == null || user.getParty().getQuest() == null) {
|
||||
return false;
|
||||
}
|
||||
return !isQuestActive() && user.getParty().getQuest().RSVPNeeded;
|
||||
}
|
||||
|
||||
private boolean isQuestActive() {
|
||||
return quest != null && quest.active;
|
||||
}
|
||||
|
||||
|
||||
private void updateQuestContent(QuestContent questContent) {
|
||||
if (questTitleView == null) {
|
||||
return;
|
||||
}
|
||||
questTitleView.setText(questContent.getText());
|
||||
questDescriptionView.setText(MarkdownParser.parseMarkdown(questContent.getNotes()));
|
||||
DataBindingUtils.loadImage(questScrollImageView, "inventory_quest_scroll_"+questContent.getKey());
|
||||
}
|
||||
|
||||
private void setQuestParticipants(List<Member> participants) {
|
||||
if (questParticipantList == null) {
|
||||
return;
|
||||
}
|
||||
questParticipantList.removeAllViews();
|
||||
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
int participantCount = 0;
|
||||
for (Member participant : participants) {
|
||||
if (quest.active && (participant.getParticipatesInQuest() == null || !participant.getParticipatesInQuest())) {
|
||||
continue;
|
||||
}
|
||||
View participantView = inflater.inflate(R.layout.quest_participant, questParticipantList, false);
|
||||
TextView textView = (TextView) participantView.findViewById(R.id.participant_name);
|
||||
textView.setText(participant.getDisplayName());
|
||||
TextView statusTextView = (TextView) participantView.findViewById(R.id.status_view);
|
||||
if (!quest.active) {
|
||||
if (participant.getParticipatesInQuest() == null) {
|
||||
statusTextView.setText(R.string.pending);
|
||||
statusTextView.setTextColor(ContextCompat.getColor(getContext(), R.color.gray_200));
|
||||
} else if (participant.getParticipatesInQuest()) {
|
||||
statusTextView.setText(R.string.accepted);
|
||||
statusTextView.setTextColor(ContextCompat.getColor(getContext(), R.color.good_100));
|
||||
} else {
|
||||
statusTextView.setText(R.string.declined);
|
||||
statusTextView.setTextColor(ContextCompat.getColor(getContext(), R.color.worse_100));
|
||||
}
|
||||
} else {
|
||||
statusTextView.setVisibility(View.GONE);
|
||||
}
|
||||
questParticipantList.addView(participantView);
|
||||
if (quest.active || (participant.getParticipatesInQuest() != null && participant.getParticipatesInQuest())) {
|
||||
participantCount += 1;
|
||||
}
|
||||
}
|
||||
if (quest.active) {
|
||||
participantHeader.setText(R.string.participants);
|
||||
participantHeaderCount.setText(String.valueOf(participantCount));
|
||||
} else {
|
||||
participantHeader.setText(R.string.invitations);
|
||||
participantHeaderCount.setText(participantCount + "/" + quest.participants.size());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
socialRepository.close();
|
||||
userRepository.close();
|
||||
inventoryRepository.close();
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@OnClick(R.id.quest_accept_button)
|
||||
public void onQuestAccept() {
|
||||
socialRepository.acceptQuest(user, partyId).subscribe(aVoid -> {}, throwable -> {});
|
||||
}
|
||||
|
||||
|
||||
@OnClick(R.id.quest_reject_button)
|
||||
public void onQuestReject() {
|
||||
socialRepository.rejectQuest(user, partyId).subscribe(aVoid -> {}, throwable -> {});
|
||||
}
|
||||
|
||||
@OnClick(R.id.quest_begin_button)
|
||||
public void onQuestBegin() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.quest_begin_message)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> socialRepository.forceStartQuest(party)
|
||||
.subscribe(quest -> {}, throwable -> {}))
|
||||
.setNegativeButton(R.string.no, (dialog, which) -> {});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@OnClick(R.id.quest_cancel_button)
|
||||
public void onQuestCancel() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.quest_cancel_message)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> socialRepository.cancelQuest(partyId)
|
||||
.subscribe(aVoid -> {getActivity().getFragmentManager().popBackStack();}, throwable -> {})).setNegativeButton(R.string.no, (dialog, which) -> {});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@OnClick(R.id.quest_abort_button)
|
||||
public void onQuestAbort() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.quest_abort_message)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> socialRepository.abortQuest(partyId)
|
||||
.subscribe(aVoid -> {getActivity().getFragmentManager().popBackStack();}, throwable -> {})).setNegativeButton(R.string.no, (dialog, which) -> {});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectFragment(AppComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,10 @@ import com.habitrpg.android.habitica.models.inventory.QuestContent;
|
|||
import com.habitrpg.android.habitica.models.social.Group;
|
||||
import com.habitrpg.android.habitica.models.user.User;
|
||||
import com.habitrpg.android.habitica.modules.AppModule;
|
||||
import com.habitrpg.android.habitica.ui.activities.MainActivity;
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.inventory.items.ItemRecyclerFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.QuestDetailFragment;
|
||||
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils;
|
||||
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser;
|
||||
import com.habitrpg.android.habitica.ui.views.social.QuestProgressView;
|
||||
|
|
@ -75,16 +78,10 @@ public class PartyDetailFragment extends BaseFragment {
|
|||
SimpleDraweeView questImageView;
|
||||
@BindView(R.id.quest_participant_response_wrapper)
|
||||
ViewGroup questParticipantResponseWrapper;
|
||||
@BindView(R.id.quest_leader_response_wrapper)
|
||||
ViewGroup questLeaderResponseWrapper;
|
||||
@BindView(R.id.quest_accept_button)
|
||||
Button questAcceptButton;
|
||||
@BindView(R.id.quest_reject_button)
|
||||
Button questRejectButton;
|
||||
@BindView(R.id.quest_begin_button)
|
||||
Button questBeginButton;
|
||||
@BindView(R.id.quest_cancel_button)
|
||||
Button questCancelButton;
|
||||
@BindView(R.id.quest_progress_view)
|
||||
QuestProgressView questProgressView;
|
||||
@BindView(R.id.quest_participant_list)
|
||||
|
|
@ -145,7 +142,7 @@ public class PartyDetailFragment extends BaseFragment {
|
|||
titleView.setText(party.name);
|
||||
descriptionView.setText(MarkdownParser.parseMarkdown(party.description));
|
||||
|
||||
if (quest.key != null) {
|
||||
if (quest != null && quest.key != null) {
|
||||
newQuestButton.setVisibility(View.GONE);
|
||||
questDetailButton.setVisibility(View.VISIBLE);
|
||||
questImageWrapper.setVisibility(View.VISIBLE);
|
||||
|
|
@ -175,34 +172,17 @@ public class PartyDetailFragment extends BaseFragment {
|
|||
partyInvitationWrapper.setVisibility(invitationVisibility);
|
||||
}
|
||||
|
||||
if (questLeaderResponseWrapper != null) {
|
||||
if (questParticipantResponseWrapper != null) {
|
||||
if (showParticipatantButtons()) {
|
||||
questLeaderResponseWrapper.setVisibility(View.GONE);
|
||||
questParticipantResponseWrapper.setVisibility(View.VISIBLE);
|
||||
} else if (showLeaderButtons()) {
|
||||
if (isQuestActive()) {
|
||||
questLeaderResponseWrapper.setVisibility(View.GONE);
|
||||
questParticipantResponseWrapper.setVisibility(View.GONE);
|
||||
} else {
|
||||
questLeaderResponseWrapper.setVisibility(View.VISIBLE);
|
||||
questParticipantResponseWrapper.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
questLeaderResponseWrapper.setVisibility(View.GONE);
|
||||
questParticipantResponseWrapper.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean showLeaderButtons() {
|
||||
return party != null && party.quest != null && user != null && user.getId().equals(party.quest.leader);
|
||||
}
|
||||
|
||||
private boolean showParticipatantButtons() {
|
||||
if (user == null || user.getParty() == null || user.getParty().getQuest() == null) {
|
||||
return false;
|
||||
}
|
||||
return !isQuestActive() && user.getParty().getQuest().RSVPNeeded;
|
||||
return !(user == null || user.getParty() == null || user.getParty().getQuest() == null) && !isQuestActive() && user.getParty().getQuest().RSVPNeeded;
|
||||
}
|
||||
|
||||
private void updateQuestContent(QuestContent questContent) {
|
||||
|
|
@ -227,13 +207,19 @@ public class PartyDetailFragment extends BaseFragment {
|
|||
|
||||
@OnClick(R.id.new_quest_button)
|
||||
public void inviteNewQuest() {
|
||||
|
||||
ItemRecyclerFragment fragment = new ItemRecyclerFragment();
|
||||
fragment.itemType = "quests";
|
||||
fragment.itemTypeText = getString(R.string.quest);
|
||||
fragment.show(getFragmentManager(), "questDialog");
|
||||
}
|
||||
|
||||
@OnClick(R.id.leave_button)
|
||||
public void leaveParty() {
|
||||
|
||||
}
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.leave_party_confirmation)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> socialRepository.leaveGroup(partyId)
|
||||
.subscribe(aVoid -> {}, throwable -> {})).setNegativeButton(R.string.no, (dialog, which) -> {});
|
||||
builder.show(); }
|
||||
|
||||
@OnClick(R.id.quest_accept_button)
|
||||
public void onQuestAccept() {
|
||||
|
|
@ -246,25 +232,6 @@ public class PartyDetailFragment extends BaseFragment {
|
|||
socialRepository.rejectQuest(user, partyId).subscribe(aVoid -> {}, throwable -> {});
|
||||
}
|
||||
|
||||
@OnClick(R.id.quest_begin_button)
|
||||
public void onQuestBegin() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.quest_begin_message)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> socialRepository.forceStartQuest(party)
|
||||
.subscribe(quest -> {}, throwable -> {}))
|
||||
.setNegativeButton(R.string.no, (dialog, which) -> {});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@OnClick(R.id.quest_cancel_button)
|
||||
public void onQuestCancel() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.quest_cancel_message)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> socialRepository.cancelQuest(partyId)
|
||||
.subscribe(aVoid -> {}, throwable -> {})).setNegativeButton(R.string.no, (dialog, which) -> {});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@OnClick(R.id.party_invite_accept_button)
|
||||
public void onPartyInviteAccepted() {
|
||||
if (user != null) {
|
||||
|
|
@ -280,4 +247,17 @@ public class PartyDetailFragment extends BaseFragment {
|
|||
.subscribe(aVoid -> {}, RxErrorHandler.handleEmptyError());
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.quest_detail_button)
|
||||
public void questDetailButtonClicked() {
|
||||
QuestDetailFragment fragment = new QuestDetailFragment();
|
||||
fragment.partyId = partyId;
|
||||
if (party != null && party.quest != null) {
|
||||
fragment.questKey = party.quest.key;
|
||||
}
|
||||
if (getActivity() != null) {
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
activity.displayFragment(fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,18 @@ import com.google.gson.JsonSerializationContext;
|
|||
import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.habitrpg.android.habitica.models.inventory.Quest;
|
||||
import com.habitrpg.android.habitica.models.members.Member;
|
||||
import com.habitrpg.android.habitica.models.social.ChatMessage;
|
||||
import com.habitrpg.android.habitica.models.social.Group;
|
||||
import com.habitrpg.android.habitica.models.user.User;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.realm.Realm;
|
||||
import io.realm.RealmList;
|
||||
import io.realm.RealmResults;
|
||||
|
||||
public class GroupSerialization implements JsonDeserializer<Group>, JsonSerializer<Group> {
|
||||
@Override
|
||||
|
|
@ -51,13 +55,6 @@ public class GroupSerialization implements JsonDeserializer<Group>, JsonSerializ
|
|||
group.chat = context.deserialize(obj.get("chat"), new TypeToken<RealmList<ChatMessage>>() {
|
||||
}.getType());
|
||||
}
|
||||
if (obj.has("members")) {
|
||||
JsonArray memberList = obj.get("members").getAsJsonArray();
|
||||
if (memberList.size() > 0 && memberList.get(0).isJsonObject()) {
|
||||
group.members = context.deserialize(memberList, new TypeToken<List<User>>() {
|
||||
}.getType());
|
||||
}
|
||||
}
|
||||
if (obj.has("leader")) {
|
||||
if (obj.get("leader").isJsonPrimitive()) {
|
||||
group.leaderID = obj.get("leader").getAsString();
|
||||
|
|
@ -74,6 +71,37 @@ public class GroupSerialization implements JsonDeserializer<Group>, JsonSerializ
|
|||
group.quest = context.deserialize(obj.get("quest"), new TypeToken<Quest>() {
|
||||
}.getType());
|
||||
group.quest.id = group.id;
|
||||
|
||||
if (obj.getAsJsonObject("quest").has("members")) {
|
||||
JsonObject members = obj.getAsJsonObject("quest").getAsJsonObject("members");
|
||||
Realm realm = Realm.getDefaultInstance();
|
||||
List<Member> dbMembers = realm.copyFromRealm(realm.where(Member.class).equalTo("party.id", group.id).findAll());
|
||||
realm.close();
|
||||
for (Member member : dbMembers) {
|
||||
if (members.has(member.getId())) {
|
||||
JsonElement value = members.get(member.getId());
|
||||
if (value.isJsonNull()) {
|
||||
member.setParticipatesInQuest(null);
|
||||
} else {
|
||||
member.setParticipatesInQuest(value.getAsBoolean());
|
||||
}
|
||||
} else {
|
||||
member.setParticipatesInQuest(null);
|
||||
}
|
||||
members.remove(member.getId());
|
||||
}
|
||||
for (Map.Entry<String, JsonElement> entry : members.entrySet()) {
|
||||
Member member = new Member();
|
||||
member.setId(entry.getKey());
|
||||
if (!entry.getValue().isJsonNull()) {
|
||||
member.setParticipatesInQuest(entry.getValue().getAsBoolean());
|
||||
}
|
||||
dbMembers.add(member);
|
||||
}
|
||||
RealmList<Member> newMembers = new RealmList<>();
|
||||
newMembers.addAll(dbMembers);
|
||||
group.quest.participants = newMembers;
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
|
|
|
|||
|
|
@ -23,11 +23,15 @@ import io.realm.Realm;
|
|||
public class MemberSerialization implements JsonDeserializer<Member> {
|
||||
@Override
|
||||
public Member deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
Member member = new Member();
|
||||
JsonObject obj = json.getAsJsonObject();
|
||||
String id = obj.get("_id").getAsString();
|
||||
|
||||
if (obj.has("_id")) {
|
||||
member.setId(obj.get("_id").getAsString());
|
||||
Realm realm = Realm.getDefaultInstance();
|
||||
Member member = realm.where(Member.class).equalTo("id", id).findFirst();
|
||||
if (member == null) {
|
||||
member = new Member();
|
||||
} else {
|
||||
member = realm.copyFromRealm(member);
|
||||
}
|
||||
|
||||
if (obj.has("stats")) {
|
||||
|
|
@ -47,7 +51,6 @@ public class MemberSerialization implements JsonDeserializer<Member> {
|
|||
if (member.getParty() != null && member.getParty().getQuest() != null) {
|
||||
member.getParty().getQuest().id = member.getId();
|
||||
if (!obj.get("party").getAsJsonObject().get("quest").getAsJsonObject().has("RSVPNeeded")) {
|
||||
Realm realm = Realm.getDefaultInstance();
|
||||
Quest quest = realm.where(Quest.class).equalTo("id", member.getId()).findFirst();
|
||||
if (quest != null && quest.isValid()) {
|
||||
member.getParty().getQuest().RSVPNeeded = quest.RSVPNeeded;
|
||||
|
|
@ -81,6 +84,7 @@ public class MemberSerialization implements JsonDeserializer<Member> {
|
|||
member.setContributor(context.deserialize(obj.get("contributor"), ContributorInfo.class));
|
||||
}
|
||||
|
||||
realm.close();
|
||||
return member;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue