diff --git a/mastodon/build.gradle b/mastodon/build.gradle index 0c91a95fc..fd6be97f0 100644 --- a/mastodon/build.gradle +++ b/mastodon/build.gradle @@ -13,7 +13,7 @@ android { applicationId "org.joinmastodon.android" minSdk 23 targetSdk 34 - versionCode 117 + versionCode 118 versionName "2.7.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/mastodon/proguard-rules.pro b/mastodon/proguard-rules.pro index bafd000a9..4e6cca71a 100644 --- a/mastodon/proguard-rules.pro +++ b/mastodon/proguard-rules.pro @@ -35,7 +35,7 @@ *; } --keepnames public class org.joinmastodon.android.api.session**{ +-keepnames public class org.joinmastodon.android.api.session.**{ *; } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountActivationInfo.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountActivationInfo.java index 43e5739ae..b920f9fad 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountActivationInfo.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountActivationInfo.java @@ -1,7 +1,11 @@ package org.joinmastodon.android.api.session; +import com.google.gson.annotations.SerializedName; + public class AccountActivationInfo{ + @SerializedName(value="email", alternate="a") public String email; + @SerializedName(value="last_email_confirmation_resend", alternate="b") public long lastEmailConfirmationResend; public AccountActivationInfo(String email, long lastEmailConfirmationResend){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java index 4e2921ccb..fc82d7f90 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java @@ -9,6 +9,7 @@ import android.util.Log; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; import org.joinmastodon.android.E; @@ -30,7 +31,6 @@ import org.joinmastodon.android.model.Application; import org.joinmastodon.android.model.FilterAction; import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.FilterResult; -import org.joinmastodon.android.model.FollowList; import org.joinmastodon.android.model.Instance; import org.joinmastodon.android.model.LegacyFilter; import org.joinmastodon.android.model.Preferences; @@ -57,21 +57,37 @@ public class AccountSession{ public static final int FLAG_ACTIVATED=1; public static final int FLAG_NEED_UPDATE_PUSH_SETTINGS=1 << 1; + @SerializedName(value="token", alternate="a") public Token token; + @SerializedName(value="self", alternate="b") public Account self; + @SerializedName(value="domain", alternate="c") public String domain; + @SerializedName(value="app", alternate="d") public Application app; + @SerializedName(value="info_last_updated", alternate="e") public long infoLastUpdated; + @SerializedName(value="activated", alternate="f") public boolean activated=true; + @SerializedName(value="push_private_key", alternate="g") public String pushPrivateKey; + @SerializedName(value="push_public_key", alternate="h") public String pushPublicKey; + @SerializedName(value="push_auth_key", alternate="i") public String pushAuthKey; + @SerializedName(value="push_subscription", alternate="j") public PushSubscription pushSubscription; + @SerializedName(value="need_update_push_settings", alternate="k") public boolean needUpdatePushSettings; + @SerializedName(value="filters_last_updated", alternate="l") public long filtersLastUpdated; + @SerializedName(value="word_filters", alternate="m") public List wordFilters=new ArrayList<>(); + @SerializedName(value="push_account_i_d", alternate="n") public String pushAccountID; + @SerializedName(value="activation_info", alternate="o") public AccountActivationInfo activationInfo; + @SerializedName(value="preferences", alternate="p") public Preferences preferences; private transient MastodonAPIController apiController; private transient StatusInteractionController statusInteractionController; diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java index 66c3279e6..da11930db 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java @@ -19,6 +19,7 @@ import android.net.Uri; import android.os.Build; import android.util.Log; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -649,6 +650,7 @@ public class AccountSessionManager{ `last_updated` bigint, `version` integer NOT NULL DEFAULT 1 )"""); + maybeMigrateAccounts(db); } @Override @@ -662,37 +664,7 @@ public class AccountSessionManager{ `emojis` text, `last_updated` bigint )"""); - - File accountsFile=new File(MastodonApp.context.getFilesDir(), "accounts.json"); - if(accountsFile.exists()){ - HashSet domains=new HashSet<>(); - try(FileInputStream in=new FileInputStream(accountsFile)){ - JsonObject jobj=JsonParser.parseReader(new InputStreamReader(in, StandardCharsets.UTF_8)).getAsJsonObject(); - ContentValues values=new ContentValues(); - for(JsonElement jacc:jobj.getAsJsonArray("accounts")){ - AccountSession session=MastodonAPIController.gson.fromJson(jacc, AccountSession.class); - domains.add(session.domain.toLowerCase()); - session.toContentValues(values); - db.insertWithOnConflict("accounts", null, values, SQLiteDatabase.CONFLICT_REPLACE); - } - }catch(Exception x){ - Log.e(TAG, "Error migrating accounts", x); - return; - } - accountsFile.delete(); - for(String domain:domains){ - File file=new File(MastodonApp.context.getFilesDir(), "instance_"+domain.replace('.', '_')+".json"); - try(FileInputStream in=new FileInputStream(file)){ - JsonObject jobj=JsonParser.parseReader(new InputStreamReader(in, StandardCharsets.UTF_8)).getAsJsonObject(); - - insertInstanceIntoDatabase(db, domain, MastodonAPIController.gson.fromJson(jobj.get("instance"), Instance.class), - MastodonAPIController.gson.fromJson(jobj.get("emojis"), new TypeToken<>(){}.getType()), jobj.get("last_updated").getAsLong()); - }catch(Exception x){ - Log.w(TAG, "Error reading instance info file for "+domain, x); - } - file.delete(); - } - } + maybeMigrateAccounts(db); } if(oldVersion<3){ db.execSQL("ALTER TABLE `instances` ADD `version` integer NOT NULL DEFAULT 1"); @@ -717,5 +689,39 @@ public class AccountSessionManager{ `preferences` text )"""); } + + private void maybeMigrateAccounts(SQLiteDatabase db){ + File accountsFile=new File(MastodonApp.context.getFilesDir(), "accounts.json"); + if(accountsFile.exists()){ + HashSet domains=new HashSet<>(); + try(FileInputStream in=new FileInputStream(accountsFile)){ + JsonObject jobj=JsonParser.parseReader(new InputStreamReader(in, StandardCharsets.UTF_8)).getAsJsonObject(); + ContentValues values=new ContentValues(); + JsonArray accounts=jobj.has("a") ? jobj.getAsJsonArray("a") : jobj.getAsJsonArray("accounts"); + for(JsonElement jacc:accounts){ + AccountSession session=MastodonAPIController.gson.fromJson(jacc, AccountSession.class); + domains.add(session.domain.toLowerCase()); + session.toContentValues(values); + db.insertWithOnConflict("accounts", null, values, SQLiteDatabase.CONFLICT_REPLACE); + } + }catch(Exception x){ + Log.e(TAG, "Error migrating accounts", x); + return; + } + accountsFile.delete(); + for(String domain:domains){ + File file=new File(MastodonApp.context.getFilesDir(), "instance_"+domain.replace('.', '_')+".json"); + try(FileInputStream in=new FileInputStream(file)){ + JsonObject jobj=JsonParser.parseReader(new InputStreamReader(in, StandardCharsets.UTF_8)).getAsJsonObject(); + + insertInstanceIntoDatabase(db, domain, MastodonAPIController.gson.fromJson(jobj.get("instance"), Instance.class), + MastodonAPIController.gson.fromJson(jobj.get("emojis"), new TypeToken<>(){}.getType()), jobj.get("last_updated").getAsLong()); + }catch(Exception x){ + Log.w(TAG, "Error reading instance info file for "+domain, x); + } + file.delete(); + } + } + } } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeFragment.java index 97062abd0..fb2f18d11 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeFragment.java @@ -30,6 +30,7 @@ import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent; import org.joinmastodon.android.fragments.discover.DiscoverFragment; import org.joinmastodon.android.fragments.onboarding.OnboardingFollowSuggestionsFragment; import org.joinmastodon.android.model.Account; +import org.joinmastodon.android.model.Instance; import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.NotificationType; import org.joinmastodon.android.ui.OutlineProviders; @@ -291,7 +292,10 @@ public class HomeFragment extends AppKitFragment{ } private void reloadNotificationsForUnreadCount(){ - if(AccountSessionManager.get(accountID).getInstanceInfo().getApiVersion()>=2){ + Instance instance=AccountSessionManager.get(accountID).getInstanceInfo(); + if(instance==null) + return; + if(instance.getApiVersion()>=2){ new GetUnreadNotificationsCount() .setCallback(new Callback<>(){ @Override