mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-04-14 11:46:32 +00:00
fix various crashes
This commit is contained in:
parent
64827c3f89
commit
6a529b31d0
26 changed files with 115 additions and 29 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="1926"
|
||||
android:versionName="1.1.6"
|
||||
android:versionCode="1928"
|
||||
android:versionName="1.2"
|
||||
android:screenOrientation="portrait"
|
||||
android:installLocation="auto" >
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<string name="SP_APIToken" translatable="false">APIToken</string>
|
||||
<string name="SP_username" translatable="false">Username</string>
|
||||
<string name="SP_email" translatable="false">E-mail</string>
|
||||
<string name="base_url" translatable="false">https://habitica.com</string>
|
||||
<string name="base_url" translatable="false">https://habitrpg-staging.herokuapp.com</string>
|
||||
|
||||
<!-- Local notification actions -->
|
||||
<string name="accept_party_invite" translatable="false">ACCEPT_PARTY_INVITE</string>
|
||||
|
|
|
|||
|
|
@ -10,4 +10,6 @@ public interface BaseRepository {
|
|||
|
||||
<T extends RealmObject> T getUnmanagedCopy(T object);
|
||||
<T extends RealmObject> List<T> getUnmanagedCopy(List<T> list);
|
||||
|
||||
boolean isClosed();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.habitrpg.android.habitica.data;
|
||||
|
||||
import com.habitrpg.android.habitica.models.AchievementResult;
|
||||
import com.habitrpg.android.habitica.models.inventory.Quest;
|
||||
import com.habitrpg.android.habitica.models.members.Member;
|
||||
import com.habitrpg.android.habitica.models.responses.PostChatMessageResult;
|
||||
|
|
@ -72,4 +73,6 @@ public interface SocialRepository extends BaseRepository {
|
|||
Observable<Void> rejectGroupInvite(String groupId);
|
||||
|
||||
Observable<Quest> forceStartQuest(Group party);
|
||||
|
||||
Observable<AchievementResult> getMemberAchievements(String userId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.util.Log;
|
|||
import com.amplitude.api.Amplitude;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.habitrpg.android.habitica.BuildConfig;
|
||||
import com.habitrpg.android.habitica.HabiticaBaseApplication;
|
||||
|
|
@ -117,7 +118,6 @@ import okhttp3.ResponseBody;
|
|||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import retrofit2.Converter;
|
||||
import retrofit2.HttpException;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
|
@ -157,6 +157,7 @@ public class ApiClientImpl implements Action1<Throwable>, ApiClient {
|
|||
.doOnError(this);
|
||||
private AlertDialog displayedAlert;
|
||||
private String languageCode;
|
||||
private String lastAPICallURL;
|
||||
|
||||
//private OnHabitsAPIResult mResultListener;
|
||||
//private HostConfig mConfig;
|
||||
|
|
@ -194,8 +195,10 @@ public class ApiClientImpl implements Action1<Throwable>, ApiClient {
|
|||
if (userAgent != null) {
|
||||
builder = builder.header("user-agent", userAgent);
|
||||
}
|
||||
builder = builder.addHeader("Authorization", "Basic " + BuildConfig.STAGING_KEY);
|
||||
Request request = builder.method(original.method(), original.body())
|
||||
.build();
|
||||
lastAPICallURL = original.url().toString();
|
||||
return chain.proceed(request);
|
||||
})
|
||||
.build();
|
||||
|
|
@ -326,18 +329,23 @@ public class ApiClientImpl implements Action1<Throwable>, ApiClient {
|
|||
} else {
|
||||
showConnectionProblemDialog(R.string.internal_error_api);
|
||||
}
|
||||
} else if (JsonSyntaxException.class.isAssignableFrom(throwableClass)) {
|
||||
crashlyticsProxy.log("Json Error: " + lastAPICallURL + ", " + throwable.getMessage());
|
||||
} else {
|
||||
crashlyticsProxy.logException(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public ErrorResponse getErrorResponse(HttpException error) {
|
||||
Response<?> response = error.response();
|
||||
ResponseBody errorResponse = error.response().errorBody();
|
||||
if (errorResponse == null) {
|
||||
return new ErrorResponse();
|
||||
}
|
||||
Converter<ResponseBody, ?> errorConverter =
|
||||
gsonConverter
|
||||
.responseBodyConverter(ErrorResponse.class, new Annotation[0], retrofitAdapter);
|
||||
try {
|
||||
return (ErrorResponse) errorConverter.convert(response.errorBody());
|
||||
return (ErrorResponse) errorConverter.convert(errorResponse);
|
||||
} catch (IOException e) {
|
||||
return new ErrorResponse();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@ public abstract class BaseRepositoryImpl<T extends BaseLocalRepository> implemen
|
|||
return localRepository.getUnmanagedCopy(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return localRepository.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends RealmObject> T getUnmanagedCopy(T object) {
|
||||
return localRepository.getUnmanagedCopy(object);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.habitrpg.android.habitica.data.ApiClient;
|
|||
import com.habitrpg.android.habitica.data.SocialRepository;
|
||||
import com.habitrpg.android.habitica.data.local.SocialLocalRepository;
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler;
|
||||
import com.habitrpg.android.habitica.models.AchievementResult;
|
||||
import com.habitrpg.android.habitica.models.inventory.Quest;
|
||||
import com.habitrpg.android.habitica.models.members.Member;
|
||||
import com.habitrpg.android.habitica.models.responses.PostChatMessageResult;
|
||||
|
|
@ -18,8 +19,6 @@ import java.util.Map;
|
|||
|
||||
import io.realm.RealmResults;
|
||||
import rx.Observable;
|
||||
import rx.functions.Action1;
|
||||
import rx.functions.Func2;
|
||||
|
||||
|
||||
public class SocialRepositoryImpl extends BaseRepositoryImpl<SocialLocalRepository> implements SocialRepository {
|
||||
|
|
@ -55,11 +54,17 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl<SocialLocalReposito
|
|||
|
||||
@Override
|
||||
public Observable<Void> flagMessage(ChatMessage chatMessage) {
|
||||
if (chatMessage.id == null) {
|
||||
return Observable.just(null);
|
||||
}
|
||||
return apiClient.flagMessage(chatMessage.groupId, chatMessage.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<ChatMessage> likeMessage(ChatMessage chatMessage) {
|
||||
if (chatMessage.id == null) {
|
||||
return Observable.just(null);
|
||||
}
|
||||
boolean liked = chatMessage.userLikesMessage(userId);
|
||||
localRepository.likeMessage(chatMessage, userId, !liked);
|
||||
return apiClient.likeMessage(chatMessage.groupId, chatMessage.id)
|
||||
|
|
@ -115,7 +120,7 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl<SocialLocalReposito
|
|||
@Override
|
||||
public Observable<Group> leaveGroup(String id) {
|
||||
return apiClient.leaveGroup(id)
|
||||
.flatMap(aVoid -> localRepository.getGroup(id))
|
||||
.flatMap(aVoid -> localRepository.getGroup(id).first())
|
||||
.doOnNext(group -> localRepository.executeTransaction(realm -> group.isMember = false));
|
||||
}
|
||||
|
||||
|
|
@ -198,6 +203,9 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl<SocialLocalReposito
|
|||
|
||||
@Override
|
||||
public Observable<Member> getMember(String userId) {
|
||||
if (userId == null) {
|
||||
return Observable.just(null);
|
||||
}
|
||||
return apiClient.getMember(userId);
|
||||
}
|
||||
|
||||
|
|
@ -251,4 +259,12 @@ public class SocialRepositoryImpl extends BaseRepositoryImpl<SocialLocalReposito
|
|||
return apiClient.forceStartQuest(party.id, localRepository.getUnmanagedCopy(party))
|
||||
.doOnNext(aVoid -> localRepository.setQuestActivity(party, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<AchievementResult> getMemberAchievements(String userId) {
|
||||
if (userId == null) {
|
||||
return Observable.just(null);
|
||||
}
|
||||
return apiClient.getMemberAchievements(userId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,4 +22,6 @@ public interface BaseLocalRepository {
|
|||
|
||||
<T extends RealmObject>void save(List<T> objects);
|
||||
<T extends RealmObject>void save(T object);
|
||||
|
||||
boolean isClosed();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,11 @@ abstract class RealmBaseLocalRepository implements BaseLocalRepository {
|
|||
realm.executeTransactionAsync(realm1 -> realm1.insertOrUpdate(object));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return realm.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends RealmObject> void save(List<T> objects) {
|
||||
realm.executeTransactionAsync(realm1 -> realm1.insertOrUpdate(objects));
|
||||
|
|
|
|||
|
|
@ -265,14 +265,14 @@ public class RealmInventoryLocalRepository extends RealmContentLocalRepository i
|
|||
@Override
|
||||
public void decrementMysteryItemCount(User user) {
|
||||
SpecialItem item = realm.where(SpecialItem.class).equalTo("isMysteryItem", true).findFirst();
|
||||
if (item.isValid()) {
|
||||
realm.executeTransactionAsync(realm1 -> {
|
||||
item.setOwned(item.getOwned()-1);
|
||||
if (user.getPurchased() != null && user.getPurchased().getPlan() != null) {
|
||||
user.getPurchased().getPlan().mysteryItemCount -= 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
realm.executeTransactionAsync(realm1 -> {
|
||||
if (item != null && item.isValid()) {
|
||||
item.setOwned(item.getOwned() - 1);
|
||||
}
|
||||
if (user.isValid() && user.getPurchased() != null && user.getPurchased().getPlan() != null) {
|
||||
user.getPurchased().getPlan().mysteryItemCount -= 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public class RealmSocialLocalRepository extends RealmBaseLocalRepository impleme
|
|||
public Observable<Group> getGroup(String id) {
|
||||
return realm.where(Group.class)
|
||||
.equalTo("id", id)
|
||||
.findAllAsync()
|
||||
.findAll()
|
||||
.asObservable()
|
||||
.filter(group -> group.isLoaded() && group.isValid() && !group.isEmpty())
|
||||
.map(groups -> groups.first());
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import java.io.IOException;
|
|||
|
||||
import cz.msebera.android.httpclient.HttpException;
|
||||
import rx.functions.Action1;
|
||||
import rx.plugins.RxJavaHooks;
|
||||
|
||||
public class RxErrorHandler {
|
||||
|
||||
|
|
@ -18,6 +19,8 @@ public class RxErrorHandler {
|
|||
public static void init(CrashlyticsProxy crashlyticsProxy) {
|
||||
instance = new RxErrorHandler();
|
||||
instance.crashlyticsProxy = crashlyticsProxy;
|
||||
|
||||
RxJavaHooks.setOnError(handleEmptyError());
|
||||
}
|
||||
|
||||
public static Action1<Throwable> handleEmptyError() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.models.members;
|
|||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.habitrpg.android.habitica.models.Avatar;
|
||||
import com.habitrpg.android.habitica.models.social.UserParty;
|
||||
import com.habitrpg.android.habitica.models.user.Buffs;
|
||||
|
|
@ -24,6 +25,7 @@ public class Member extends RealmObject implements Avatar {
|
|||
|
||||
|
||||
@PrimaryKey
|
||||
@SerializedName("_id")
|
||||
private String id;
|
||||
private Stats stats;
|
||||
private Inbox inbox;
|
||||
|
|
|
|||
|
|
@ -15,4 +15,6 @@ public interface CrashlyticsProxy {
|
|||
void setUserName(String name);
|
||||
|
||||
void fabricLogE(String s1, String s2, Exception e);
|
||||
|
||||
void log(String msg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,4 +35,9 @@ public class EmptyCrashlyticsProxy implements CrashlyticsProxy {
|
|||
public void fabricLogE(String s1, String s2, Exception e) {
|
||||
//pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String msg) {
|
||||
//pass
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -441,7 +441,11 @@ public class CreateChallengeActivity extends BaseActivity {
|
|||
|
||||
checkPrizeAndMinimumForTavern();
|
||||
|
||||
challengeRepository.getChallengeTasks(challengeId).subscribe(tasks -> tasks.tasks.forEach((s, task) -> addOrUpdateTaskInList(task)), RxErrorHandler.handleEmptyError(), () -> {
|
||||
challengeRepository.getChallengeTasks(challengeId).subscribe(tasks -> {
|
||||
for (Task task : tasks.tasks.values()) {
|
||||
addOrUpdateTaskInList(task);
|
||||
}
|
||||
}, RxErrorHandler.handleEmptyError(), () -> {
|
||||
// activate editMode to track taskChanges
|
||||
editMode = true;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ public class FullProfileActivity extends BaseActivity {
|
|||
//mountsTamedCount.setText(String.valueOf(user.getMountsTamedCount()));
|
||||
|
||||
// Load the members achievements now
|
||||
apiClient.getMemberAchievements(this.userId).subscribe(this::fillAchievements, RxErrorHandler.handleEmptyError());
|
||||
socialRepository.getMemberAchievements(this.userId).subscribe(this::fillAchievements, RxErrorHandler.handleEmptyError());
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
|
@ -261,6 +261,9 @@ public class FullProfileActivity extends BaseActivity {
|
|||
// region Attributes
|
||||
|
||||
private void fillAchievements(AchievementResult achievements) {
|
||||
if (achievements == null) {
|
||||
return;
|
||||
}
|
||||
List<Object> items = new ArrayList<>();
|
||||
|
||||
fillAchievements(achievements.basic, items);
|
||||
|
|
|
|||
|
|
@ -294,6 +294,10 @@ public class SubscriptionFragment extends BaseFragment implements GemPurchaseAct
|
|||
}
|
||||
}
|
||||
|
||||
if (this.subscriptionDetailsView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSubscribed) {
|
||||
this.subscriptionDetailsView.setVisibility(View.VISIBLE);
|
||||
this.subscriptionDetailsView.setPlan(plan);
|
||||
|
|
|
|||
|
|
@ -186,7 +186,9 @@ public class InboxFragment extends BaseMainFragment
|
|||
|
||||
public void onUserReceived(User user) {
|
||||
this.user = user;
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
if (swipeRefreshLayout != null) {
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -114,7 +114,11 @@ public class QuestDetailFragment extends BaseMainFragment {
|
|||
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());
|
||||
socialRepository.getMember(quest.leader).first().subscribe(member -> {
|
||||
if (getContext() != null && questLeaderView != null) {
|
||||
questLeaderView.setText(getContext().getString(R.string.quest_leader_header, member.getDisplayName()));
|
||||
}
|
||||
}, RxErrorHandler.handleEmptyError());
|
||||
|
||||
if (questLeaderResponseWrapper != null) {
|
||||
if (showParticipatantButtons()) {
|
||||
|
|
|
|||
|
|
@ -134,7 +134,11 @@ public class PartyDetailFragment extends BaseFragment {
|
|||
if (refreshLayout != null) {
|
||||
refreshLayout.setRefreshing(false);
|
||||
}
|
||||
}, throwable -> refreshLayout.setRefreshing(false));
|
||||
}, throwable -> {
|
||||
if (refreshLayout != null) {
|
||||
refreshLayout.setRefreshing(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateParty(Group party) {
|
||||
|
|
@ -191,7 +195,7 @@ public class PartyDetailFragment extends BaseFragment {
|
|||
}
|
||||
|
||||
private void updateQuestContent(QuestContent questContent) {
|
||||
if (questTitleView == null) {
|
||||
if (questTitleView == null && questContent.isManaged()) {
|
||||
return;
|
||||
}
|
||||
questTitleView.setText(questContent.getText());
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ public class YesterdailyDialog extends AlertDialog {
|
|||
if (userRepository != null && userId != null) {
|
||||
Observable.just(null)
|
||||
.delay(500, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
|
||||
.filter(aVoid -> !userRepository.isClosed())
|
||||
.flatMap(aVoid -> userRepository.getUser(userId))
|
||||
.first()
|
||||
.filter(user -> user != null && user.getNeedsCron() != null && user.getNeedsCron())
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ public class MemberSerialization implements JsonDeserializer<Member> {
|
|||
Member member = realm.where(Member.class).equalTo("id", id).findFirst();
|
||||
if (member == null) {
|
||||
member = new Member();
|
||||
member.setId(id);
|
||||
} else {
|
||||
member = realm.copyFromRealm(member);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.google.gson.JsonArray;
|
|||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.internal.LinkedTreeMap;
|
||||
import com.habitrpg.android.habitica.models.tasks.Task;
|
||||
import com.habitrpg.android.habitica.models.tasks.TaskList;
|
||||
|
||||
|
|
@ -24,10 +25,14 @@ public class TaskListDeserializer implements JsonDeserializer<TaskList> {
|
|||
Map<String, Task> taskMap = new HashMap<>();
|
||||
|
||||
for (JsonElement e : json.getAsJsonArray()) {
|
||||
Task task = ctx.deserialize(e, Task.class);
|
||||
//Workaround, since gson doesn't call setter methods
|
||||
task.setId(task.getId());
|
||||
taskMap.put(task.getId(), task);
|
||||
try {
|
||||
Task task = ctx.deserialize(e, Task.class);
|
||||
//Workaround, since gson doesn't call setter methods
|
||||
task.setId(task.getId());
|
||||
taskMap.put(task.getId(), task);
|
||||
} catch (ClassCastException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tasks.tasks = taskMap;
|
||||
|
|
|
|||
|
|
@ -47,4 +47,9 @@ public class CrashlyticsProxyImpl implements CrashlyticsProxy {
|
|||
public void fabricLogE(String s1, String s2, Exception e) {
|
||||
Fabric.getLogger().e(s1,s2,e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String msg) {
|
||||
Crashlytics.getInstance().log(msg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
org.gradle.configureondemand=true
|
||||
org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
org.gradle.jvmargs=-Xmx6656M
|
||||
Loading…
Reference in a new issue