Add support for /api/v2/instance
This commit is contained in:
@@ -1,10 +1,8 @@
|
|||||||
package org.joinmastodon.android.test;
|
package org.joinmastodon.android.test;
|
||||||
|
|
||||||
import android.app.Instrumentation;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
@@ -14,7 +12,7 @@ import org.joinmastodon.android.GlobalUserPreferences;
|
|||||||
import org.joinmastodon.android.MainActivity;
|
import org.joinmastodon.android.MainActivity;
|
||||||
import org.joinmastodon.android.MastodonApp;
|
import org.joinmastodon.android.MastodonApp;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
import org.joinmastodon.android.api.requests.instance.GetInstanceV2;
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
|
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
@@ -22,6 +20,7 @@ import org.joinmastodon.android.fragments.ComposeFragment;
|
|||||||
import org.joinmastodon.android.fragments.ThreadFragment;
|
import org.joinmastodon.android.fragments.ThreadFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.InstanceRulesFragment;
|
import org.joinmastodon.android.fragments.onboarding.InstanceRulesFragment;
|
||||||
import org.joinmastodon.android.model.Instance;
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
import org.joinmastodon.android.model.InstanceV2;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
@@ -32,12 +31,9 @@ import org.parceler.Parcels;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.BrokenBarrierException;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.CyclicBarrier;
|
import java.util.concurrent.CyclicBarrier;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import androidx.test.core.app.ActivityScenario;
|
|
||||||
import androidx.test.espresso.PerformException;
|
import androidx.test.espresso.PerformException;
|
||||||
import androidx.test.espresso.UiController;
|
import androidx.test.espresso.UiController;
|
||||||
import androidx.test.espresso.ViewAction;
|
import androidx.test.espresso.ViewAction;
|
||||||
@@ -47,19 +43,19 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
import androidx.test.platform.app.InstrumentationRegistry;
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
import androidx.test.runner.screenshot.ScreenCapture;
|
|
||||||
import androidx.test.runner.screenshot.Screenshot;
|
import androidx.test.runner.screenshot.Screenshot;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import okio.BufferedSink;
|
import okio.BufferedSink;
|
||||||
import okio.Okio;
|
import okio.Okio;
|
||||||
import okio.Sink;
|
|
||||||
import okio.Source;
|
import okio.Source;
|
||||||
|
|
||||||
import static androidx.test.espresso.Espresso.*;
|
import static androidx.test.espresso.Espresso.onView;
|
||||||
import static androidx.test.espresso.action.ViewActions.*;
|
import static androidx.test.espresso.action.ViewActions.typeText;
|
||||||
import static androidx.test.espresso.assertion.ViewAssertions.*;
|
import static androidx.test.espresso.matcher.ViewMatchers.Visibility;
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.*;
|
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@@ -148,10 +144,10 @@ public class StoreScreenshotsGenerator{
|
|||||||
takeScreenshot("Thread");
|
takeScreenshot("Thread");
|
||||||
|
|
||||||
Instance[] _instance={null};
|
Instance[] _instance={null};
|
||||||
new GetInstance()
|
new GetInstanceV2()
|
||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Instance result){
|
public void onSuccess(InstanceV2 result){
|
||||||
_instance[0]=result;
|
_instance[0]=result;
|
||||||
try{
|
try{
|
||||||
barrier.await();
|
barrier.await();
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import android.content.Intent;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
||||||
@@ -79,7 +78,7 @@ public class OAuthActivity extends Activity{
|
|||||||
progress.dismiss();
|
progress.dismiss();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(instance.uri, token);
|
.exec(instance.getDomain(), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -88,7 +87,7 @@ public class OAuthActivity extends Activity{
|
|||||||
progress.dismiss();
|
progress.dismiss();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.execNoAuth(instance.uri);
|
.execNoAuth(instance.getDomain());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleError(ErrorResponse error){
|
private void handleError(ErrorResponse error){
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package org.joinmastodon.android.api;
|
||||||
|
|
||||||
|
import me.grishka.appkit.api.APIRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a different API request to allow a chain of requests to be canceled
|
||||||
|
*/
|
||||||
|
public class WrapperRequest<T> extends APIRequest<T>{
|
||||||
|
public APIRequest<?> wrappedRequest;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel(){
|
||||||
|
if(wrappedRequest!=null)
|
||||||
|
wrappedRequest.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public APIRequest<T> exec(){
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package org.joinmastodon.android.api.requests.instance;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
|
||||||
import org.joinmastodon.android.model.Instance;
|
|
||||||
|
|
||||||
public class GetInstance extends MastodonAPIRequest<Instance>{
|
|
||||||
public GetInstance(){
|
|
||||||
super(HttpMethod.GET, "/instance", Instance.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package org.joinmastodon.android.api.requests.instance;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.model.InstanceV1;
|
||||||
|
|
||||||
|
public class GetInstanceV1 extends MastodonAPIRequest<InstanceV1>{
|
||||||
|
public GetInstanceV1(){
|
||||||
|
super(HttpMethod.GET, "/instance", InstanceV1.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.joinmastodon.android.api.requests.instance;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.model.InstanceV2;
|
||||||
|
|
||||||
|
public class GetInstanceV2 extends MastodonAPIRequest<InstanceV2>{
|
||||||
|
public GetInstanceV2(){
|
||||||
|
super(HttpMethod.GET, "/instance", InstanceV2.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPathPrefix(){
|
||||||
|
return "/api/v2";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,12 +32,15 @@ import org.joinmastodon.android.R;
|
|||||||
import org.joinmastodon.android.api.CacheController;
|
import org.joinmastodon.android.api.CacheController;
|
||||||
import org.joinmastodon.android.api.DatabaseRunnable;
|
import org.joinmastodon.android.api.DatabaseRunnable;
|
||||||
import org.joinmastodon.android.api.MastodonAPIController;
|
import org.joinmastodon.android.api.MastodonAPIController;
|
||||||
|
import org.joinmastodon.android.api.MastodonErrorResponse;
|
||||||
import org.joinmastodon.android.api.PushSubscriptionManager;
|
import org.joinmastodon.android.api.PushSubscriptionManager;
|
||||||
|
import org.joinmastodon.android.api.WrapperRequest;
|
||||||
import org.joinmastodon.android.api.gson.JsonObjectBuilder;
|
import org.joinmastodon.android.api.gson.JsonObjectBuilder;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
||||||
import org.joinmastodon.android.api.requests.filters.GetLegacyFilters;
|
import org.joinmastodon.android.api.requests.filters.GetLegacyFilters;
|
||||||
import org.joinmastodon.android.api.requests.instance.GetCustomEmojis;
|
import org.joinmastodon.android.api.requests.instance.GetCustomEmojis;
|
||||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
import org.joinmastodon.android.api.requests.instance.GetInstanceV1;
|
||||||
|
import org.joinmastodon.android.api.requests.instance.GetInstanceV2;
|
||||||
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
|
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
|
||||||
import org.joinmastodon.android.events.EmojiUpdatedEvent;
|
import org.joinmastodon.android.events.EmojiUpdatedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
@@ -45,6 +48,8 @@ import org.joinmastodon.android.model.Application;
|
|||||||
import org.joinmastodon.android.model.Emoji;
|
import org.joinmastodon.android.model.Emoji;
|
||||||
import org.joinmastodon.android.model.EmojiCategory;
|
import org.joinmastodon.android.model.EmojiCategory;
|
||||||
import org.joinmastodon.android.model.Instance;
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
import org.joinmastodon.android.model.InstanceV1;
|
||||||
|
import org.joinmastodon.android.model.InstanceV2;
|
||||||
import org.joinmastodon.android.model.LegacyFilter;
|
import org.joinmastodon.android.model.LegacyFilter;
|
||||||
import org.joinmastodon.android.model.Preferences;
|
import org.joinmastodon.android.model.Preferences;
|
||||||
import org.joinmastodon.android.model.Token;
|
import org.joinmastodon.android.model.Token;
|
||||||
@@ -67,6 +72,7 @@ import java.util.stream.Collectors;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.browser.customtabs.CustomTabsIntent;
|
import androidx.browser.customtabs.CustomTabsIntent;
|
||||||
|
import me.grishka.appkit.api.APIRequest;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
|
|
||||||
@@ -74,7 +80,7 @@ public class AccountSessionManager{
|
|||||||
private static final String TAG="AccountSessionManager";
|
private static final String TAG="AccountSessionManager";
|
||||||
public static final String SCOPE="read write follow push";
|
public static final String SCOPE="read write follow push";
|
||||||
public static final String REDIRECT_URI="mastodon-android-auth://callback";
|
public static final String REDIRECT_URI="mastodon-android-auth://callback";
|
||||||
private static final int DB_VERSION=2;
|
private static final int DB_VERSION=3;
|
||||||
|
|
||||||
private static final AccountSessionManager instance=new AccountSessionManager();
|
private static final AccountSessionManager instance=new AccountSessionManager();
|
||||||
|
|
||||||
@@ -116,8 +122,8 @@ public class AccountSessionManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addAccount(Instance instance, Token token, Account self, Application app, AccountActivationInfo activationInfo){
|
public void addAccount(Instance instance, Token token, Account self, Application app, AccountActivationInfo activationInfo){
|
||||||
instances.put(instance.uri, instance);
|
instances.put(instance.getDomain(), instance);
|
||||||
AccountSession session=new AccountSession(token, self, app, instance.uri, activationInfo==null, activationInfo);
|
AccountSession session=new AccountSession(token, self, app, instance.getDomain(), activationInfo==null, activationInfo);
|
||||||
sessions.put(session.getID(), session);
|
sessions.put(session.getID(), session);
|
||||||
lastActiveAccountID=session.getID();
|
lastActiveAccountID=session.getID();
|
||||||
runOnDbThread(db->{
|
runOnDbThread(db->{
|
||||||
@@ -125,7 +131,7 @@ public class AccountSessionManager{
|
|||||||
session.toContentValues(values);
|
session.toContentValues(values);
|
||||||
db.insertWithOnConflict("accounts", null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
db.insertWithOnConflict("accounts", null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||||
});
|
});
|
||||||
updateInstanceEmojis(instance, instance.uri);
|
updateInstanceEmojis(instance, instance.getDomain());
|
||||||
if(PushSubscriptionManager.arePushNotificationsAvailable()){
|
if(PushSubscriptionManager.arePushNotificationsAvailable()){
|
||||||
session.getPushSubscriptionManager().registerAccountForPush(null);
|
session.getPushSubscriptionManager().registerAccountForPush(null);
|
||||||
}
|
}
|
||||||
@@ -224,7 +230,7 @@ public class AccountSessionManager{
|
|||||||
authenticatingApp=result;
|
authenticatingApp=result;
|
||||||
Uri uri=new Uri.Builder()
|
Uri uri=new Uri.Builder()
|
||||||
.scheme("https")
|
.scheme("https")
|
||||||
.authority(instance.uri)
|
.authority(instance.getDomain())
|
||||||
.path("/oauth/authorize")
|
.path("/oauth/authorize")
|
||||||
.appendQueryParameter("response_type", "code")
|
.appendQueryParameter("response_type", "code")
|
||||||
.appendQueryParameter("client_id", result.clientId)
|
.appendQueryParameter("client_id", result.clientId)
|
||||||
@@ -245,7 +251,7 @@ public class AccountSessionManager{
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.wrapProgress(activity, R.string.preparing_auth, false)
|
.wrapProgress(activity, R.string.preparing_auth, false)
|
||||||
.execNoAuth(instance.uri);
|
.execNoAuth(instance.getDomain());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSelf(String id, Account other){
|
public boolean isSelf(String id, Account other){
|
||||||
@@ -337,8 +343,7 @@ public class AccountSessionManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateInstanceInfo(String domain){
|
public void updateInstanceInfo(String domain){
|
||||||
new GetInstance()
|
loadInstanceInfo(domain, new Callback<>(){
|
||||||
.setCallback(new Callback<>(){
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Instance instance){
|
public void onSuccess(Instance instance){
|
||||||
instances.put(domain, instance);
|
instances.put(domain, instance);
|
||||||
@@ -349,8 +354,7 @@ public class AccountSessionManager{
|
|||||||
public void onError(ErrorResponse error){
|
public void onError(ErrorResponse error){
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.execNoAuth(domain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateInstanceEmojis(Instance instance, String domain){
|
private void updateInstanceEmojis(Instance instance, String domain){
|
||||||
@@ -379,7 +383,12 @@ public class AccountSessionManager{
|
|||||||
while(cursor.moveToNext()){
|
while(cursor.moveToNext()){
|
||||||
DatabaseUtils.cursorRowToContentValues(cursor, values);
|
DatabaseUtils.cursorRowToContentValues(cursor, values);
|
||||||
String domain=values.getAsString("domain");
|
String domain=values.getAsString("domain");
|
||||||
Instance instance=MastodonAPIController.gson.fromJson(values.getAsString("instance_obj"), Instance.class);
|
int version=values.getAsInteger("version");
|
||||||
|
Instance instance=MastodonAPIController.gson.fromJson(values.getAsString("instance_obj"), switch(version){
|
||||||
|
case 1 -> InstanceV1.class;
|
||||||
|
case 2 -> InstanceV2.class;
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: " + version);
|
||||||
|
});
|
||||||
List<Emoji> emojis=MastodonAPIController.gson.fromJson(values.getAsString("emojis"), new TypeToken<List<Emoji>>(){}.getType());
|
List<Emoji> emojis=MastodonAPIController.gson.fromJson(values.getAsString("emojis"), new TypeToken<List<Emoji>>(){}.getType());
|
||||||
instances.put(domain, instance);
|
instances.put(domain, instance);
|
||||||
customEmojis.put(domain, groupCustomEmojis(emojis));
|
customEmojis.put(domain, groupCustomEmojis(emojis));
|
||||||
@@ -575,9 +584,49 @@ public class AccountSessionManager{
|
|||||||
values.put("instance_obj", MastodonAPIController.gson.toJson(instance));
|
values.put("instance_obj", MastodonAPIController.gson.toJson(instance));
|
||||||
values.put("emojis", MastodonAPIController.gson.toJson(emojis));
|
values.put("emojis", MastodonAPIController.gson.toJson(emojis));
|
||||||
values.put("last_updated", lastUpdated);
|
values.put("last_updated", lastUpdated);
|
||||||
|
values.put("version", instance.getVersion());
|
||||||
db.insertWithOnConflict("instances", null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
db.insertWithOnConflict("instances", null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static APIRequest<Instance> loadInstanceInfo(String domain, Callback<Instance> callback){
|
||||||
|
final WrapperRequest<Instance> wrapper=new WrapperRequest<>();
|
||||||
|
wrapper.wrappedRequest=new GetInstanceV2()
|
||||||
|
.setCallback(new Callback<>(){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(InstanceV2 result){
|
||||||
|
wrapper.wrappedRequest=null;
|
||||||
|
callback.onSuccess(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error){
|
||||||
|
if(error instanceof MastodonErrorResponse mr && mr.httpStatus==404){
|
||||||
|
// Mastodon pre-4.0 or a non-Mastodon server altogether. Let's try /api/v1/instance
|
||||||
|
wrapper.wrappedRequest=new GetInstanceV1()
|
||||||
|
.setCallback(new Callback<>(){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(InstanceV1 result){
|
||||||
|
wrapper.wrappedRequest=null;
|
||||||
|
callback.onSuccess(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error){
|
||||||
|
wrapper.wrappedRequest=null;
|
||||||
|
callback.onError(error);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.execNoAuth(domain);
|
||||||
|
}else{
|
||||||
|
wrapper.wrappedRequest=null;
|
||||||
|
callback.onError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.execNoAuth(domain);
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
private static class DatabaseHelper extends SQLiteOpenHelper{
|
private static class DatabaseHelper extends SQLiteOpenHelper{
|
||||||
public DatabaseHelper(){
|
public DatabaseHelper(){
|
||||||
super(MastodonApp.context, "accounts.db", null, DB_VERSION);
|
super(MastodonApp.context, "accounts.db", null, DB_VERSION);
|
||||||
@@ -590,13 +639,28 @@ public class AccountSessionManager{
|
|||||||
`id` text PRIMARY KEY,
|
`id` text PRIMARY KEY,
|
||||||
`dismissed_at` bigint
|
`dismissed_at` bigint
|
||||||
)""");
|
)""");
|
||||||
createAccountsAndInstancesTables(db);
|
createAccountsTable(db);
|
||||||
|
db.execSQL("""
|
||||||
|
CREATE TABLE `instances` (
|
||||||
|
`domain` text PRIMARY KEY,
|
||||||
|
`instance_obj` text,
|
||||||
|
`emojis` text,
|
||||||
|
`last_updated` bigint,
|
||||||
|
`version` integer NOT NULL DEFAULT 1
|
||||||
|
)""");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
|
||||||
if(oldVersion<2){
|
if(oldVersion<2){
|
||||||
createAccountsAndInstancesTables(db);
|
createAccountsTable(db);
|
||||||
|
db.execSQL("""
|
||||||
|
CREATE TABLE `instances` (
|
||||||
|
`domain` text PRIMARY KEY,
|
||||||
|
`instance_obj` text,
|
||||||
|
`emojis` text,
|
||||||
|
`last_updated` bigint
|
||||||
|
)""");
|
||||||
|
|
||||||
File accountsFile=new File(MastodonApp.context.getFilesDir(), "accounts.json");
|
File accountsFile=new File(MastodonApp.context.getFilesDir(), "accounts.json");
|
||||||
if(accountsFile.exists()){
|
if(accountsFile.exists()){
|
||||||
@@ -629,9 +693,12 @@ public class AccountSessionManager{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(oldVersion<3){
|
||||||
|
db.execSQL("ALTER TABLE `instances` ADD `version` integer NOT NULL DEFAULT 1");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createAccountsAndInstancesTables(SQLiteDatabase db){
|
private void createAccountsTable(SQLiteDatabase db){
|
||||||
db.execSQL("""
|
db.execSQL("""
|
||||||
CREATE TABLE `accounts` (
|
CREATE TABLE `accounts` (
|
||||||
`id` text PRIMARY KEY,
|
`id` text PRIMARY KEY,
|
||||||
@@ -648,13 +715,6 @@ public class AccountSessionManager{
|
|||||||
`activation_info` text,
|
`activation_info` text,
|
||||||
`preferences` text
|
`preferences` text
|
||||||
)""");
|
)""");
|
||||||
db.execSQL("""
|
|
||||||
CREATE TABLE `instances` (
|
|
||||||
`domain` text PRIMARY KEY,
|
|
||||||
`instance_obj` text,
|
|
||||||
`emojis` text,
|
|
||||||
`last_updated` bigint
|
|
||||||
)""");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,13 @@ import org.joinmastodon.android.R;
|
|||||||
import org.joinmastodon.android.api.MastodonErrorResponse;
|
import org.joinmastodon.android.api.MastodonErrorResponse;
|
||||||
import org.joinmastodon.android.api.requests.accounts.CheckInviteLink;
|
import org.joinmastodon.android.api.requests.accounts.CheckInviteLink;
|
||||||
import org.joinmastodon.android.api.requests.catalog.GetCatalogDefaultInstances;
|
import org.joinmastodon.android.api.requests.catalog.GetCatalogDefaultInstances;
|
||||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
import org.joinmastodon.android.api.requests.instance.GetInstanceV1;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.onboarding.InstanceCatalogSignupFragment;
|
import org.joinmastodon.android.fragments.onboarding.InstanceCatalogSignupFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.InstanceChooserLoginFragment;
|
import org.joinmastodon.android.fragments.onboarding.InstanceChooserLoginFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.InstanceRulesFragment;
|
import org.joinmastodon.android.fragments.onboarding.InstanceRulesFragment;
|
||||||
import org.joinmastodon.android.model.Instance;
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
import org.joinmastodon.android.model.InstanceV1;
|
||||||
import org.joinmastodon.android.model.catalog.CatalogDefaultInstance;
|
import org.joinmastodon.android.model.catalog.CatalogDefaultInstance;
|
||||||
import org.joinmastodon.android.ui.InterpolatingMotionEffect;
|
import org.joinmastodon.android.ui.InterpolatingMotionEffect;
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
@@ -172,15 +174,14 @@ public class SplashFragment extends AppKitFragment{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void proceedWithServerDomain(String domain){
|
private void proceedWithServerDomain(String domain){
|
||||||
new GetInstance()
|
AccountSessionManager.loadInstanceInfo(domain, new Callback<>(){
|
||||||
.setCallback(new Callback<>(){
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Instance result){
|
public void onSuccess(Instance result){
|
||||||
if(getActivity()==null)
|
if(getActivity()==null)
|
||||||
return;
|
return;
|
||||||
instanceLoadingProgress.dismiss();
|
instanceLoadingProgress.dismiss();
|
||||||
instanceLoadingProgress=null;
|
instanceLoadingProgress=null;
|
||||||
if(!result.registrations && TextUtils.isEmpty(inviteCode)){
|
if(!result.areRegistrationsOpen() && TextUtils.isEmpty(inviteCode)){
|
||||||
new M3AlertDialogBuilder(getActivity())
|
new M3AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.error)
|
.setTitle(R.string.error)
|
||||||
.setMessage(R.string.instance_signup_closed)
|
.setMessage(R.string.instance_signup_closed)
|
||||||
@@ -203,8 +204,7 @@ public class SplashFragment extends AppKitFragment{
|
|||||||
instanceLoadingProgress=null;
|
instanceLoadingProgress=null;
|
||||||
error.showToast(getActivity());
|
error.showToast(getActivity());
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.execNoAuth(domain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onLearnMoreClick(View v){
|
private void onLearnMoreClick(View v){
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.onboarding;
|
package org.joinmastodon.android.fragments.onboarding;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -11,14 +8,11 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.MastodonAPIController;
|
import org.joinmastodon.android.api.MastodonAPIController;
|
||||||
import org.joinmastodon.android.model.Instance;
|
import org.joinmastodon.android.model.Instance;
|
||||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
|
||||||
import org.joinmastodon.android.ui.OutlineProviders;
|
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.utils.ElevationOnScrollListener;
|
import org.joinmastodon.android.utils.ElevationOnScrollListener;
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
@@ -26,7 +20,6 @@ import org.jsoup.nodes.Document;
|
|||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -36,14 +29,10 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.fragments.AppKitFragment;
|
|
||||||
import me.grishka.appkit.fragments.ToolbarFragment;
|
import me.grishka.appkit.fragments.ToolbarFragment;
|
||||||
import me.grishka.appkit.imageloader.ViewImageLoader;
|
|
||||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
|
||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||||
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
|
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
|
||||||
import me.grishka.appkit.utils.V;
|
|
||||||
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
@@ -99,7 +88,7 @@ public class GoogleMadeMeAddThisFragment extends ToolbarFragment{
|
|||||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
View headerView=inflater.inflate(R.layout.item_list_header_simple, list, false);
|
View headerView=inflater.inflate(R.layout.item_list_header_simple, list, false);
|
||||||
TextView text=headerView.findViewById(R.id.text);
|
TextView text=headerView.findViewById(R.id.text);
|
||||||
text.setText(getString(R.string.privacy_policy_subtitle, instance.uri));
|
text.setText(getString(R.string.privacy_policy_subtitle, instance.getDomain()));
|
||||||
|
|
||||||
adapter=new MergeRecyclerAdapter();
|
adapter=new MergeRecyclerAdapter();
|
||||||
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
||||||
@@ -111,7 +100,7 @@ public class GoogleMadeMeAddThisFragment extends ToolbarFragment{
|
|||||||
buttonBar=view.findViewById(R.id.button_bar);
|
buttonBar=view.findViewById(R.id.button_bar);
|
||||||
|
|
||||||
Button backBtn=view.findViewById(R.id.btn_back);
|
Button backBtn=view.findViewById(R.id.btn_back);
|
||||||
backBtn.setText(getString(R.string.server_policy_disagree, instance.uri));
|
backBtn.setText(getString(R.string.server_policy_disagree, instance.getDomain()));
|
||||||
backBtn.setOnClickListener(v->{
|
backBtn.setOnClickListener(v->{
|
||||||
setResult(false, null);
|
setResult(false, null);
|
||||||
Nav.finish(this);
|
Nav.finish(this);
|
||||||
@@ -159,7 +148,7 @@ public class GoogleMadeMeAddThisFragment extends ToolbarFragment{
|
|||||||
|
|
||||||
private void loadServerPrivacyPolicy(){
|
private void loadServerPrivacyPolicy(){
|
||||||
Request req=new Request.Builder()
|
Request req=new Request.Builder()
|
||||||
.url("https://"+instance.uri+"/terms")
|
.url("https://"+instance.getDomain()+"/terms")
|
||||||
.addHeader("Accept-Language", Locale.getDefault().toLanguageTag())
|
.addHeader("Accept-Language", Locale.getDefault().toLanguageTag())
|
||||||
.build();
|
.build();
|
||||||
currentRequest=MastodonAPIController.getHttpClient().newCall(req);
|
currentRequest=MastodonAPIController.getHttpClient().newCall(req);
|
||||||
@@ -176,7 +165,7 @@ public class GoogleMadeMeAddThisFragment extends ToolbarFragment{
|
|||||||
if(!response.isSuccessful())
|
if(!response.isSuccessful())
|
||||||
return;
|
return;
|
||||||
Document doc=Jsoup.parse(Objects.requireNonNull(body).byteStream(), Objects.requireNonNull(body.contentType()).charset(StandardCharsets.UTF_8).name(), req.url().toString());
|
Document doc=Jsoup.parse(Objects.requireNonNull(body).byteStream(), Objects.requireNonNull(body.contentType()).charset(StandardCharsets.UTF_8).name(), req.url().toString());
|
||||||
final Item item=new Item(doc.title(), null, instance.uri, req.url().toString(), "https://"+instance.uri+"/favicon.ico");
|
final Item item=new Item(doc.title(), null, instance.getDomain(), req.url().toString(), "https://"+instance.getDomain()+"/favicon.ico");
|
||||||
Activity activity=getActivity();
|
Activity activity=getActivity();
|
||||||
if(activity!=null){
|
if(activity!=null){
|
||||||
activity.runOnUiThread(()->{
|
activity.runOnUiThread(()->{
|
||||||
|
|||||||
@@ -15,8 +15,11 @@ import android.widget.TextView;
|
|||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.MastodonAPIController;
|
import org.joinmastodon.android.api.MastodonAPIController;
|
||||||
import org.joinmastodon.android.api.MastodonErrorResponse;
|
import org.joinmastodon.android.api.MastodonErrorResponse;
|
||||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
import org.joinmastodon.android.api.requests.instance.GetInstanceV1;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.model.Instance;
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
import org.joinmastodon.android.model.InstanceV1;
|
||||||
|
import org.joinmastodon.android.model.InstanceV2;
|
||||||
import org.joinmastodon.android.model.catalog.CatalogInstance;
|
import org.joinmastodon.android.model.catalog.CatalogInstance;
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
@@ -43,6 +46,7 @@ import javax.xml.parsers.DocumentBuilderFactory;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import me.grishka.appkit.api.APIRequest;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||||
@@ -63,7 +67,7 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
|
|||||||
protected HashMap<String, Instance> instancesCache=new HashMap<>();
|
protected HashMap<String, Instance> instancesCache=new HashMap<>();
|
||||||
protected View buttonBar;
|
protected View buttonBar;
|
||||||
protected List<CatalogInstance> filteredData=new ArrayList<>();
|
protected List<CatalogInstance> filteredData=new ArrayList<>();
|
||||||
protected GetInstance loadingInstanceRequest;
|
protected APIRequest<Instance> loadingInstanceRequest;
|
||||||
protected Call loadingInstanceRedirectRequest;
|
protected Call loadingInstanceRedirectRequest;
|
||||||
protected ProgressDialog instanceProgressDialog;
|
protected ProgressDialog instanceProgressDialog;
|
||||||
protected HashMap<String, String> redirects=new HashMap<>();
|
protected HashMap<String, String> redirects=new HashMap<>();
|
||||||
@@ -181,7 +185,7 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
|
|||||||
showInstanceInfoLoadError(domain, x);
|
showInstanceInfoLoadError(domain, x);
|
||||||
if(fakeInstance!=null){
|
if(fakeInstance!=null){
|
||||||
fakeInstance.description=getString(R.string.error);
|
fakeInstance.description=getString(R.string.error);
|
||||||
if(filteredData.size()>0 && filteredData.get(0)==fakeInstance){
|
if(!filteredData.isEmpty() && filteredData.get(0)==fakeInstance){
|
||||||
if(list.findViewHolderForAdapterPosition(1) instanceof BindableViewHolder<?> ivh){
|
if(list.findViewHolderForAdapterPosition(1) instanceof BindableViewHolder<?> ivh){
|
||||||
ivh.rebind();
|
ivh.rebind();
|
||||||
}
|
}
|
||||||
@@ -190,13 +194,15 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loadingInstanceDomain=domain;
|
loadingInstanceDomain=domain;
|
||||||
loadingInstanceRequest=new GetInstance();
|
loadingInstanceRequest=AccountSessionManager.loadInstanceInfo(domain, new Callback<>(){
|
||||||
loadingInstanceRequest.setCallback(new Callback<>(){
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Instance result){
|
public void onSuccess(Instance result){
|
||||||
loadingInstanceRequest=null;
|
loadingInstanceRequest=null;
|
||||||
loadingInstanceDomain=null;
|
loadingInstanceDomain=null;
|
||||||
result.uri=domain; // needed for instances that use domain redirection
|
if(result instanceof InstanceV1 v1)
|
||||||
|
v1.uri=domain; // needed for instances that use domain redirection
|
||||||
|
else if(result instanceof InstanceV2 v2)
|
||||||
|
v2.domain=domain;
|
||||||
instancesCache.put(domain, result);
|
instancesCache.put(domain, result);
|
||||||
if(instanceProgressDialog!=null || onError!=null)
|
if(instanceProgressDialog!=null || onError!=null)
|
||||||
proceedWithAuthOrSignup(result);
|
proceedWithAuthOrSignup(result);
|
||||||
@@ -246,7 +252,7 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).execNoAuth(domain);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelLoadingInstanceInfo(){
|
private void cancelLoadingInstanceInfo(){
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
|
|||||||
if(currentInviteLinkAlert!=null){
|
if(currentInviteLinkAlert!=null){
|
||||||
currentInviteLinkAlert.dismiss();
|
currentInviteLinkAlert.dismiss();
|
||||||
}else if(!TextUtils.isEmpty(currentSearchQuery) && HtmlParser.isValidInviteUrl(currentSearchQueryButWithCasePreserved)){
|
}else if(!TextUtils.isEmpty(currentSearchQuery) && HtmlParser.isValidInviteUrl(currentSearchQueryButWithCasePreserved)){
|
||||||
if(TextUtils.isEmpty(inviteCode) || !Objects.equals(instance.uri, inviteCodeHost)){
|
if(TextUtils.isEmpty(inviteCode) || !Objects.equals(instance.getDomain(), inviteCodeHost)){
|
||||||
Uri inviteLink=Uri.parse(currentSearchQueryButWithCasePreserved);
|
Uri inviteLink=Uri.parse(currentSearchQueryButWithCasePreserved);
|
||||||
new CheckInviteLink(inviteLink.getPath())
|
new CheckInviteLink(inviteLink.getPath())
|
||||||
.setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
@@ -368,9 +368,9 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
getActivity().getSystemService(InputMethodManager.class).hideSoftInputFromWindow(contentView.getWindowToken(), 0);
|
getActivity().getSystemService(InputMethodManager.class).hideSoftInputFromWindow(contentView.getWindowToken(), 0);
|
||||||
if(!instance.registrations && (TextUtils.isEmpty(inviteCode) || !Objects.equals(instance.uri, inviteCodeHost))){
|
if(!instance.areRegistrationsOpen() && (TextUtils.isEmpty(inviteCode) || !Objects.equals(instance.getDomain(), inviteCodeHost))){
|
||||||
if(instance.invitesEnabled){
|
if(instance.areInvitesEnabled()){
|
||||||
showInviteLinkAlert(instance.uri);
|
showInviteLinkAlert(instance.getDomain());
|
||||||
}else{
|
}else{
|
||||||
new M3AlertDialogBuilder(getActivity())
|
new M3AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.error)
|
.setTitle(R.string.error)
|
||||||
@@ -382,7 +382,7 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
|
|||||||
}
|
}
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putParcelable("instance", Parcels.wrap(instance));
|
args.putParcelable("instance", Parcels.wrap(instance));
|
||||||
if(!TextUtils.isEmpty(inviteCode) && Objects.equals(instance.uri, inviteCodeHost))
|
if(!TextUtils.isEmpty(inviteCode) && Objects.equals(instance.getDomain(), inviteCodeHost))
|
||||||
args.putString("inviteCode", inviteCode);
|
args.putString("inviteCode", inviteCode);
|
||||||
Nav.go(getActivity(), InstanceRulesFragment.class, args);
|
Nav.go(getActivity(), InstanceRulesFragment.class, args);
|
||||||
}
|
}
|
||||||
@@ -667,7 +667,7 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
|
|||||||
radioButton.setChecked(chosenInstance==item);
|
radioButton.setChecked(chosenInstance==item);
|
||||||
Instance realInstance=instancesCache.get(item.normalizedDomain);
|
Instance realInstance=instancesCache.get(item.normalizedDomain);
|
||||||
float alpha;
|
float alpha;
|
||||||
if(realInstance!=null && !realInstance.registrations){
|
if(realInstance!=null && !realInstance.areRegistrationsOpen()){
|
||||||
alpha=0.38f;
|
alpha=0.38f;
|
||||||
description.setText(R.string.not_accepting_new_members);
|
description.setText(R.string.not_accepting_new_members);
|
||||||
enabled=false;
|
enabled=false;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.model.Instance;
|
import org.joinmastodon.android.model.Instance;
|
||||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
|
||||||
import org.joinmastodon.android.ui.adapters.InstanceRulesAdapter;
|
import org.joinmastodon.android.ui.adapters.InstanceRulesAdapter;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.utils.ElevationOnScrollListener;
|
import org.joinmastodon.android.utils.ElevationOnScrollListener;
|
||||||
@@ -58,7 +57,7 @@ public class InstanceRulesFragment extends ToolbarFragment{
|
|||||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
View headerView=inflater.inflate(R.layout.item_list_header_simple, list, false);
|
View headerView=inflater.inflate(R.layout.item_list_header_simple, list, false);
|
||||||
TextView text=headerView.findViewById(R.id.text);
|
TextView text=headerView.findViewById(R.id.text);
|
||||||
text.setText(Html.fromHtml(getString(R.string.instance_rules_subtitle, "<b>"+Html.escapeHtml(instance.uri)+"</b>")));
|
text.setText(Html.fromHtml(getString(R.string.instance_rules_subtitle, "<b>"+Html.escapeHtml(instance.getDomain())+"</b>")));
|
||||||
|
|
||||||
adapter=new MergeRecyclerAdapter();
|
adapter=new MergeRecyclerAdapter();
|
||||||
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ public class SignupFragment extends ToolbarFragment{
|
|||||||
passwordConfirmWrap=view.findViewById(R.id.password_confirm_wrap);
|
passwordConfirmWrap=view.findViewById(R.id.password_confirm_wrap);
|
||||||
reasonWrap=view.findViewById(R.id.reason_wrap);
|
reasonWrap=view.findViewById(R.id.reason_wrap);
|
||||||
|
|
||||||
domain.setText('@'+instance.uri);
|
domain.setText('@'+instance.getDomain());
|
||||||
|
|
||||||
username.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
|
username.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
|
||||||
@Override
|
@Override
|
||||||
@@ -143,7 +143,7 @@ public class SignupFragment extends ToolbarFragment{
|
|||||||
passwordConfirm.addTextChangedListener(new ErrorClearingListener(passwordConfirm));
|
passwordConfirm.addTextChangedListener(new ErrorClearingListener(passwordConfirm));
|
||||||
reason.addTextChangedListener(new ErrorClearingListener(reason));
|
reason.addTextChangedListener(new ErrorClearingListener(reason));
|
||||||
|
|
||||||
if(!instance.approvalRequired){
|
if(!instance.isApprovalRequired()){
|
||||||
reason.setVisibility(View.GONE);
|
reason.setVisibility(View.GONE);
|
||||||
reasonExplain.setVisibility(View.GONE);
|
reasonExplain.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
@@ -285,7 +285,7 @@ public class SignupFragment extends ToolbarFragment{
|
|||||||
progressDialog.dismiss();
|
progressDialog.dismiss();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(instance.uri, apiToken);
|
.exec(instance.getDomain(), apiToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CharSequence makeLinkInErrorMessage(String source, LinkSpan.OnLinkClickListener onClick){
|
private CharSequence makeLinkInErrorMessage(String source, LinkSpan.OnLinkClickListener onClick){
|
||||||
@@ -317,7 +317,7 @@ public class SignupFragment extends ToolbarFragment{
|
|||||||
case "email" -> switch(error.error){
|
case "email" -> switch(error.error){
|
||||||
case "ERR_BLOCKED" -> {
|
case "ERR_BLOCKED" -> {
|
||||||
String emailAddr=email.getText().toString();
|
String emailAddr=email.getText().toString();
|
||||||
String s=getResources().getString(R.string.signup_email_domain_blocked, TextUtils.htmlEncode(instance.uri), TextUtils.htmlEncode(emailAddr.substring(emailAddr.lastIndexOf('@')+1)));
|
String s=getResources().getString(R.string.signup_email_domain_blocked, TextUtils.htmlEncode(instance.getDomain()), TextUtils.htmlEncode(emailAddr.substring(emailAddr.lastIndexOf('@')+1)));
|
||||||
yield makeLinkInErrorMessage(s, this::onGoBackLinkClick);
|
yield makeLinkInErrorMessage(s, this::onGoBackLinkClick);
|
||||||
}
|
}
|
||||||
case "ERR_INVALID" -> getString(R.string.signup_email_invalid);
|
case "ERR_INVALID" -> getString(R.string.signup_email_invalid);
|
||||||
@@ -364,7 +364,7 @@ public class SignupFragment extends ToolbarFragment{
|
|||||||
private void updateButtonState(){
|
private void updateButtonState(){
|
||||||
btn.setEnabled(username.length()>0 && email.length()>0 && emailRegex.matcher(email.getText()).find()
|
btn.setEnabled(username.length()>0 && email.length()>0 && emailRegex.matcher(email.getText()).find()
|
||||||
&& password.length()>=8 && passwordConfirm.length()>=8 && password.getText().toString().equals(passwordConfirm.getText().toString())
|
&& password.length()>=8 && passwordConfirm.length()>=8 && password.getText().toString().equals(passwordConfirm.getText().toString())
|
||||||
&& (!instance.approvalRequired || reason.length()>0));
|
&& (!instance.isApprovalRequired() || reason.length()>0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createAppAndGetToken(){
|
private void createAppAndGetToken(){
|
||||||
@@ -386,7 +386,7 @@ public class SignupFragment extends ToolbarFragment{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.execNoAuth(instance.uri);
|
.execNoAuth(instance.getDomain());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getToken(){
|
private void getToken(){
|
||||||
@@ -412,7 +412,7 @@ public class SignupFragment extends ToolbarFragment{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.execNoAuth(instance.uri);
|
.execNoAuth(instance.getDomain());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -426,7 +426,7 @@ public class SignupFragment extends ToolbarFragment{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onForgotPasswordLinkClick(LinkSpan span){
|
private void onForgotPasswordLinkClick(LinkSpan span){
|
||||||
UiUtils.launchWebBrowser(getActivity(), "https://"+instance.uri+"/auth/password/new");
|
UiUtils.launchWebBrowser(getActivity(), "https://"+instance.getDomain()+"/auth/password/new");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPasswordFieldFocusChange(View v, boolean hasFocus){
|
private void onPasswordFieldFocusChange(View v, boolean hasFocus){
|
||||||
|
|||||||
@@ -100,13 +100,13 @@ public class SettingsServerAboutFragment extends LoaderFragment{
|
|||||||
scroller.setClipToPadding(false);
|
scroller.setClipToPadding(false);
|
||||||
scroller.addView(scrollingLayout);
|
scroller.addView(scrollingLayout);
|
||||||
|
|
||||||
if(!TextUtils.isEmpty(instance.thumbnail)){
|
if(!TextUtils.isEmpty(instance.getThumbnailURL())){
|
||||||
FixedAspectRatioImageView banner=new FixedAspectRatioImageView(getActivity());
|
FixedAspectRatioImageView banner=new FixedAspectRatioImageView(getActivity());
|
||||||
banner.setAspectRatio(1.914893617f);
|
banner.setAspectRatio(1.914893617f);
|
||||||
banner.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
banner.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||||
banner.setOutlineProvider(OutlineProviders.bottomRoundedRect(16));
|
banner.setOutlineProvider(OutlineProviders.bottomRoundedRect(16));
|
||||||
banner.setClipToOutline(true);
|
banner.setClipToOutline(true);
|
||||||
ViewImageLoader.loadWithoutAnimation(banner, getResources().getDrawable(R.drawable.image_placeholder, getActivity().getTheme()), new UrlImageLoaderRequest(instance.thumbnail));
|
ViewImageLoader.loadWithoutAnimation(banner, getResources().getDrawable(R.drawable.image_placeholder, getActivity().getTheme()), new UrlImageLoaderRequest(instance.getThumbnailURL()));
|
||||||
LinearLayout.LayoutParams blp=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
LinearLayout.LayoutParams blp=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
blp.bottomMargin=V.dp(24);
|
blp.bottomMargin=V.dp(24);
|
||||||
scrollingLayout.addView(banner, blp);
|
scrollingLayout.addView(banner, blp);
|
||||||
@@ -115,7 +115,7 @@ public class SettingsServerAboutFragment extends LoaderFragment{
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean needDivider=false;
|
boolean needDivider=false;
|
||||||
if(instance.contactAccount!=null){
|
if(instance.getContactAccount()!=null){
|
||||||
needDivider=true;
|
needDivider=true;
|
||||||
TextView heading=new TextView(getActivity());
|
TextView heading=new TextView(getActivity());
|
||||||
heading.setTextAppearance(R.style.m3_title_small);
|
heading.setTextAppearance(R.style.m3_title_small);
|
||||||
@@ -128,7 +128,7 @@ public class SettingsServerAboutFragment extends LoaderFragment{
|
|||||||
hlp.leftMargin=hlp.rightMargin=V.dp(16);
|
hlp.leftMargin=hlp.rightMargin=V.dp(16);
|
||||||
scrollingLayout.addView(heading, hlp);
|
scrollingLayout.addView(heading, hlp);
|
||||||
|
|
||||||
AccountViewModel model=new AccountViewModel(instance.contactAccount, accountID);
|
AccountViewModel model=new AccountViewModel(instance.getContactAccount(), accountID);
|
||||||
AccountViewHolder holder=new AccountViewHolder(this, scrollingLayout, null);
|
AccountViewHolder holder=new AccountViewHolder(this, scrollingLayout, null);
|
||||||
holder.setStyle(AccountViewHolder.AccessoryType.NONE, false);
|
holder.setStyle(AccountViewHolder.AccessoryType.NONE, false);
|
||||||
holder.bind(model);
|
holder.bind(model);
|
||||||
@@ -140,7 +140,7 @@ public class SettingsServerAboutFragment extends LoaderFragment{
|
|||||||
ViewImageLoader.load(new ViewImageLoaderHolderTarget(holder, i+1), null, model.emojiHelper.getImageRequest(i), false);
|
ViewImageLoader.load(new ViewImageLoaderHolderTarget(holder, i+1), null, model.emojiHelper.getImageRequest(i), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!TextUtils.isEmpty(instance.email)){
|
if(!TextUtils.isEmpty(instance.getContactEmail())){
|
||||||
needDivider=true;
|
needDivider=true;
|
||||||
SimpleListItemViewHolder holder=new SimpleListItemViewHolder(getActivity(), scrollingLayout);
|
SimpleListItemViewHolder holder=new SimpleListItemViewHolder(getActivity(), scrollingLayout);
|
||||||
ListItem<Void> item=new ListItem<>(R.string.send_email_to_server_admin, 0, R.drawable.ic_mail_24px, i->{});
|
ListItem<Void> item=new ListItem<>(R.string.send_email_to_server_admin, 0, R.drawable.ic_mail_24px, i->{});
|
||||||
@@ -208,7 +208,7 @@ public class SettingsServerAboutFragment extends LoaderFragment{
|
|||||||
public void onRefresh(){}
|
public void onRefresh(){}
|
||||||
|
|
||||||
private void openAdminEmail(){
|
private void openAdminEmail(){
|
||||||
Intent intent=new Intent(Intent.ACTION_VIEW, Uri.fromParts("mailto", instance.email, null));
|
Intent intent=new Intent(Intent.ACTION_VIEW, Uri.fromParts("mailto", instance.getContactEmail(), null));
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
try{
|
try{
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.joinmastodon.android.model;
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
import android.text.Html;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.api.ObjectValidationException;
|
import org.joinmastodon.android.api.ObjectValidationException;
|
||||||
import org.joinmastodon.android.api.RequiredField;
|
import org.joinmastodon.android.api.RequiredField;
|
||||||
import org.joinmastodon.android.model.catalog.CatalogInstance;
|
import org.joinmastodon.android.model.catalog.CatalogInstance;
|
||||||
@@ -10,15 +8,8 @@ import org.parceler.Parcel;
|
|||||||
import java.net.IDN;
|
import java.net.IDN;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Parcel
|
public abstract class Instance extends BaseModel{
|
||||||
public class Instance extends BaseModel{
|
|
||||||
/**
|
|
||||||
* The domain name of the instance.
|
|
||||||
*/
|
|
||||||
@RequiredField
|
|
||||||
public String uri;
|
|
||||||
/**
|
/**
|
||||||
* The title of the website.
|
* The title of the website.
|
||||||
*/
|
*/
|
||||||
@@ -29,16 +20,6 @@ public class Instance extends BaseModel{
|
|||||||
*/
|
*/
|
||||||
@RequiredField
|
@RequiredField
|
||||||
public String description;
|
public String description;
|
||||||
/**
|
|
||||||
* A shorter description defined by the admin.
|
|
||||||
*/
|
|
||||||
// @RequiredField
|
|
||||||
public String shortDescription;
|
|
||||||
/**
|
|
||||||
* An email that may be contacted for any inquiries.
|
|
||||||
*/
|
|
||||||
@RequiredField
|
|
||||||
public String email;
|
|
||||||
/**
|
/**
|
||||||
* The version of Mastodon installed on the instance.
|
* The version of Mastodon installed on the instance.
|
||||||
*/
|
*/
|
||||||
@@ -49,32 +30,7 @@ public class Instance extends BaseModel{
|
|||||||
*/
|
*/
|
||||||
// @RequiredField
|
// @RequiredField
|
||||||
public List<String> languages;
|
public List<String> languages;
|
||||||
/**
|
|
||||||
* Whether registrations are enabled.
|
|
||||||
*/
|
|
||||||
public boolean registrations;
|
|
||||||
/**
|
|
||||||
* Whether registrations require moderator approval.
|
|
||||||
*/
|
|
||||||
public boolean approvalRequired;
|
|
||||||
/**
|
|
||||||
* Whether invites are enabled.
|
|
||||||
*/
|
|
||||||
public boolean invitesEnabled;
|
|
||||||
/**
|
|
||||||
* URLs of interest for clients apps.
|
|
||||||
*/
|
|
||||||
public Map<String, String> urls;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Banner image for the website.
|
|
||||||
*/
|
|
||||||
public String thumbnail;
|
|
||||||
/**
|
|
||||||
* A user that can be contacted, as an alternative to email.
|
|
||||||
*/
|
|
||||||
public Account contactAccount;
|
|
||||||
public Stats stats;
|
|
||||||
|
|
||||||
public List<Rule> rules;
|
public List<Rule> rules;
|
||||||
public Configuration configuration;
|
public Configuration configuration;
|
||||||
@@ -85,51 +41,38 @@ public class Instance extends BaseModel{
|
|||||||
@Override
|
@Override
|
||||||
public void postprocess() throws ObjectValidationException{
|
public void postprocess() throws ObjectValidationException{
|
||||||
super.postprocess();
|
super.postprocess();
|
||||||
if(contactAccount!=null)
|
|
||||||
contactAccount.postprocess();
|
|
||||||
if(rules==null)
|
if(rules==null)
|
||||||
rules=Collections.emptyList();
|
rules=Collections.emptyList();
|
||||||
if(shortDescription==null)
|
|
||||||
shortDescription="";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(){
|
|
||||||
return "Instance{"+
|
|
||||||
"uri='"+uri+'\''+
|
|
||||||
", title='"+title+'\''+
|
|
||||||
", description='"+description+'\''+
|
|
||||||
", shortDescription='"+shortDescription+'\''+
|
|
||||||
", email='"+email+'\''+
|
|
||||||
", version='"+version+'\''+
|
|
||||||
", languages="+languages+
|
|
||||||
", registrations="+registrations+
|
|
||||||
", approvalRequired="+approvalRequired+
|
|
||||||
", invitesEnabled="+invitesEnabled+
|
|
||||||
", urls="+urls+
|
|
||||||
", thumbnail='"+thumbnail+'\''+
|
|
||||||
", contactAccount="+contactAccount+
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CatalogInstance toCatalogInstance(){
|
public CatalogInstance toCatalogInstance(){
|
||||||
CatalogInstance ci=new CatalogInstance();
|
CatalogInstance ci=new CatalogInstance();
|
||||||
ci.domain=uri;
|
ci.domain=getDomain();
|
||||||
ci.normalizedDomain=IDN.toUnicode(uri);
|
ci.normalizedDomain=IDN.toUnicode(getDomain());
|
||||||
ci.description=Html.fromHtml(shortDescription).toString().trim();
|
ci.description=description.trim();
|
||||||
if(languages!=null&&languages.size()>0){
|
if(languages!=null && !languages.isEmpty()){
|
||||||
ci.language=languages.get(0);
|
ci.language=languages.get(0);
|
||||||
ci.languages=languages;
|
ci.languages=languages;
|
||||||
}else{
|
}else{
|
||||||
ci.languages=Collections.emptyList();
|
ci.languages=List.of();
|
||||||
ci.language="unknown";
|
ci.language="unknown";
|
||||||
}
|
}
|
||||||
ci.proxiedThumbnail=thumbnail;
|
ci.proxiedThumbnail=getThumbnailURL();
|
||||||
if(stats!=null)
|
// if(stats!=null)
|
||||||
ci.totalUsers=stats.userCount;
|
// ci.totalUsers=stats.userCount;
|
||||||
return ci;
|
return ci;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract String getDomain();
|
||||||
|
public abstract Account getContactAccount();
|
||||||
|
public abstract String getContactEmail();
|
||||||
|
public abstract boolean areRegistrationsOpen();
|
||||||
|
public abstract boolean isApprovalRequired();
|
||||||
|
public abstract boolean areInvitesEnabled();
|
||||||
|
public abstract String getThumbnailURL();
|
||||||
|
public abstract int getVersion();
|
||||||
|
public abstract long getApiVersion(String name);
|
||||||
|
|
||||||
@Parcel
|
@Parcel
|
||||||
public static class Rule{
|
public static class Rule{
|
||||||
public String id;
|
public String id;
|
||||||
@@ -138,13 +81,6 @@ public class Instance extends BaseModel{
|
|||||||
public transient CharSequence parsedText;
|
public transient CharSequence parsedText;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parcel
|
|
||||||
public static class Stats{
|
|
||||||
public int userCount;
|
|
||||||
public int statusCount;
|
|
||||||
public int domainCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Parcel
|
@Parcel
|
||||||
public static class Configuration{
|
public static class Configuration{
|
||||||
public StatusesConfiguration statuses;
|
public StatusesConfiguration statuses;
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.ObjectValidationException;
|
||||||
|
import org.joinmastodon.android.api.RequiredField;
|
||||||
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Parcel
|
||||||
|
public class InstanceV1 extends Instance{
|
||||||
|
/**
|
||||||
|
* The domain name of the instance.
|
||||||
|
*/
|
||||||
|
@RequiredField
|
||||||
|
public String uri;
|
||||||
|
/**
|
||||||
|
* A shorter description defined by the admin.
|
||||||
|
*/
|
||||||
|
// @RequiredField
|
||||||
|
public String shortDescription;
|
||||||
|
/**
|
||||||
|
* An email that may be contacted for any inquiries.
|
||||||
|
*/
|
||||||
|
@RequiredField
|
||||||
|
public String email;
|
||||||
|
/**
|
||||||
|
* Whether registrations are enabled.
|
||||||
|
*/
|
||||||
|
public boolean registrations;
|
||||||
|
/**
|
||||||
|
* Whether registrations require moderator approval.
|
||||||
|
*/
|
||||||
|
public boolean approvalRequired;
|
||||||
|
/**
|
||||||
|
* Whether invites are enabled.
|
||||||
|
*/
|
||||||
|
public boolean invitesEnabled;
|
||||||
|
/**
|
||||||
|
* URLs of interest for clients apps.
|
||||||
|
*/
|
||||||
|
public Map<String, String> urls;
|
||||||
|
/**
|
||||||
|
* A user that can be contacted, as an alternative to email.
|
||||||
|
*/
|
||||||
|
public Account contactAccount;
|
||||||
|
public Stats stats;
|
||||||
|
/**
|
||||||
|
* Banner image for the website.
|
||||||
|
*/
|
||||||
|
public String thumbnail;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain(){
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Account getContactAccount(){
|
||||||
|
return contactAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContactEmail(){
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areInvitesEnabled(){
|
||||||
|
return invitesEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areRegistrationsOpen(){
|
||||||
|
return registrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApprovalRequired(){
|
||||||
|
return approvalRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getThumbnailURL(){
|
||||||
|
return thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVersion(){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getApiVersion(String name){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postprocess() throws ObjectValidationException{
|
||||||
|
super.postprocess();
|
||||||
|
if(shortDescription==null)
|
||||||
|
shortDescription="";
|
||||||
|
if(contactAccount!=null)
|
||||||
|
contactAccount.postprocess();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parcel
|
||||||
|
public static class Stats{
|
||||||
|
public int userCount;
|
||||||
|
public int statusCount;
|
||||||
|
public int domainCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.ObjectValidationException;
|
||||||
|
import org.joinmastodon.android.api.RequiredField;
|
||||||
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Parcel
|
||||||
|
public class InstanceV2 extends Instance{
|
||||||
|
@RequiredField
|
||||||
|
public String domain;
|
||||||
|
public Thumbnail thumbnail;
|
||||||
|
@RequiredField
|
||||||
|
public Registrations registrations;
|
||||||
|
public Contact contact;
|
||||||
|
public Map<String, Long> apiVersions;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain(){
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Account getContactAccount(){
|
||||||
|
return contact!=null ? contact.account : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContactEmail(){
|
||||||
|
return contact!=null ? contact.email : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areRegistrationsOpen(){
|
||||||
|
return registrations.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApprovalRequired(){
|
||||||
|
return registrations.approvalRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areInvitesEnabled(){
|
||||||
|
return true; // TODO are they though?
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getThumbnailURL(){
|
||||||
|
return thumbnail!=null ? thumbnail.url : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVersion(){
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getApiVersion(String name){
|
||||||
|
if(apiVersions==null)
|
||||||
|
return 0;
|
||||||
|
Long v=apiVersions.get(name);
|
||||||
|
return v==null ? 0 : v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postprocess() throws ObjectValidationException{
|
||||||
|
super.postprocess();
|
||||||
|
if(contact!=null && contact.account!=null)
|
||||||
|
contact.account.postprocess();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parcel
|
||||||
|
public static class Thumbnail{
|
||||||
|
public String url;
|
||||||
|
public String blurhash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parcel
|
||||||
|
public static class Registrations{
|
||||||
|
public boolean enabled;
|
||||||
|
public boolean approvalRequired;
|
||||||
|
public String message;
|
||||||
|
public String url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parcel
|
||||||
|
public static class Contact{
|
||||||
|
public String email;
|
||||||
|
public Account account;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user