Make the default server configurable
This commit is contained in:
parent
85d4c1fc24
commit
d8dfa6017d
|
@ -9,8 +9,8 @@ android {
|
||||||
applicationId "org.joinmastodon.android"
|
applicationId "org.joinmastodon.android"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 60
|
versionCode 61
|
||||||
versionName "2.0.0"
|
versionName "2.0.1"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "da-rDK", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fa-rIR", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "ig-rNG", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "my-rMM", "nl-rNL", "no-rNO", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "ur-rIN", "vi-rVN", "zh-rCN", "zh-rTW"
|
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "da-rDK", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fa-rIR", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "ig-rNG", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "my-rMM", "nl-rNL", "no-rNO", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "ur-rIN", "vi-rVN", "zh-rCN", "zh-rTW"
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -86,6 +87,9 @@ public class MastodonAPIController{
|
||||||
synchronized(req){
|
synchronized(req){
|
||||||
req.okhttpCall=call;
|
req.okhttpCall=call;
|
||||||
}
|
}
|
||||||
|
if(req.timeout>0){
|
||||||
|
call.timeout().timeout(req.timeout, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
if(BuildConfig.DEBUG)
|
if(BuildConfig.DEBUG)
|
||||||
Log.d(TAG, "["+(session==null ? "no-auth" : session.getID())+"] Sending request: "+hreq);
|
Log.d(TAG, "["+(session==null ? "no-auth" : session.getID())+"] Sending request: "+hreq);
|
||||||
|
|
|
@ -45,6 +45,7 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
|
||||||
Token token;
|
Token token;
|
||||||
boolean canceled;
|
boolean canceled;
|
||||||
Map<String, String> headers;
|
Map<String, String> headers;
|
||||||
|
long timeout;
|
||||||
private ProgressDialog progressDialog;
|
private ProgressDialog progressDialog;
|
||||||
protected boolean removeUnsupportedItems;
|
protected boolean removeUnsupportedItems;
|
||||||
|
|
||||||
|
@ -127,6 +128,10 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
|
||||||
headers.put(key, value);
|
headers.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setTimeout(long timeout){
|
||||||
|
this.timeout=timeout;
|
||||||
|
}
|
||||||
|
|
||||||
protected String getPathPrefix(){
|
protected String getPathPrefix(){
|
||||||
return "/api/v1";
|
return "/api/v1";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.joinmastodon.android.api.requests.catalog;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.model.catalog.CatalogDefaultInstance;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GetCatalogDefaultInstances extends MastodonAPIRequest<List<CatalogDefaultInstance>>{
|
||||||
|
public GetCatalogDefaultInstances(){
|
||||||
|
super(HttpMethod.GET, null, new TypeToken<>(){});
|
||||||
|
setTimeout(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getURL(){
|
||||||
|
return Uri.parse("https://api.joinmastodon.org/default-servers");
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,20 +7,27 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.widget.Button;
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
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.catalog.GetCatalogDefaultInstances;
|
||||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
||||||
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.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.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
||||||
import org.joinmastodon.android.ui.views.SizeListenerFrameLayout;
|
import org.joinmastodon.android.ui.views.SizeListenerFrameLayout;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
|
@ -37,11 +44,16 @@ public class SplashFragment extends AppKitFragment{
|
||||||
private View artContainer, blueFill, greenFill;
|
private View artContainer, blueFill, greenFill;
|
||||||
private InterpolatingMotionEffect motionEffect;
|
private InterpolatingMotionEffect motionEffect;
|
||||||
private View artClouds, artPlaneElephant, artRightHill, artLeftHill, artCenterHill;
|
private View artClouds, artPlaneElephant, artRightHill, artLeftHill, artCenterHill;
|
||||||
|
private ProgressBarButton defaultServerButton;
|
||||||
|
private ProgressBar defaultServerProgress;
|
||||||
|
private String chosenDefaultServer=DEFAULT_SERVER;
|
||||||
|
private boolean loadingDefaultServer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
motionEffect=new InterpolatingMotionEffect(MastodonApp.context);
|
motionEffect=new InterpolatingMotionEffect(MastodonApp.context);
|
||||||
|
loadAndChooseDefaultServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -50,9 +62,14 @@ public class SplashFragment extends AppKitFragment{
|
||||||
contentView=(SizeListenerFrameLayout) inflater.inflate(R.layout.fragment_splash, container, false);
|
contentView=(SizeListenerFrameLayout) inflater.inflate(R.layout.fragment_splash, container, false);
|
||||||
contentView.findViewById(R.id.btn_get_started).setOnClickListener(this::onButtonClick);
|
contentView.findViewById(R.id.btn_get_started).setOnClickListener(this::onButtonClick);
|
||||||
contentView.findViewById(R.id.btn_log_in).setOnClickListener(this::onButtonClick);
|
contentView.findViewById(R.id.btn_log_in).setOnClickListener(this::onButtonClick);
|
||||||
Button joinDefault=contentView.findViewById(R.id.btn_join_default_server);
|
defaultServerButton=contentView.findViewById(R.id.btn_join_default_server);
|
||||||
joinDefault.setText(getString(R.string.join_default_server, DEFAULT_SERVER));
|
defaultServerButton.setText(getString(R.string.join_default_server, chosenDefaultServer));
|
||||||
joinDefault.setOnClickListener(this::onJoinDefaultServerClick);
|
defaultServerButton.setOnClickListener(this::onJoinDefaultServerClick);
|
||||||
|
defaultServerProgress=contentView.findViewById(R.id.action_progress);
|
||||||
|
if(loadingDefaultServer){
|
||||||
|
defaultServerButton.setTextVisible(false);
|
||||||
|
defaultServerProgress.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
contentView.findViewById(R.id.btn_learn_more).setOnClickListener(this::onLearnMoreClick);
|
contentView.findViewById(R.id.btn_learn_more).setOnClickListener(this::onLearnMoreClick);
|
||||||
|
|
||||||
artClouds=contentView.findViewById(R.id.art_clouds);
|
artClouds=contentView.findViewById(R.id.art_clouds);
|
||||||
|
@ -96,12 +113,22 @@ public class SplashFragment extends AppKitFragment{
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onJoinDefaultServerClick(View v){
|
private void onJoinDefaultServerClick(View v){
|
||||||
|
if(loadingDefaultServer)
|
||||||
|
return;
|
||||||
new GetInstance()
|
new GetInstance()
|
||||||
.setCallback(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;
|
||||||
|
if(!result.registrations){
|
||||||
|
new M3AlertDialogBuilder(getActivity())
|
||||||
|
.setTitle(R.string.error)
|
||||||
|
.setMessage(R.string.instance_signup_closed)
|
||||||
|
.setPositiveButton(R.string.ok, null)
|
||||||
|
.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putParcelable("instance", Parcels.wrap(result));
|
args.putParcelable("instance", Parcels.wrap(result));
|
||||||
Nav.go(getActivity(), InstanceRulesFragment.class, args);
|
Nav.go(getActivity(), InstanceRulesFragment.class, args);
|
||||||
|
@ -115,7 +142,7 @@ public class SplashFragment extends AppKitFragment{
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.wrapProgress(getActivity(), R.string.loading_instance, true)
|
.wrapProgress(getActivity(), R.string.loading_instance, true)
|
||||||
.execNoAuth(DEFAULT_SERVER);
|
.execNoAuth(chosenDefaultServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onLearnMoreClick(View v){
|
private void onLearnMoreClick(View v){
|
||||||
|
@ -168,4 +195,54 @@ public class SplashFragment extends AppKitFragment{
|
||||||
super.onHidden();
|
super.onHidden();
|
||||||
motionEffect.deactivate();
|
motionEffect.deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadAndChooseDefaultServer(){
|
||||||
|
loadingDefaultServer=true;
|
||||||
|
new GetCatalogDefaultInstances()
|
||||||
|
.setCallback(new Callback<>(){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(List<CatalogDefaultInstance> result){
|
||||||
|
if(result.isEmpty()){
|
||||||
|
setChosenDefaultServer(DEFAULT_SERVER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float sum=0f;
|
||||||
|
for(CatalogDefaultInstance inst:result){
|
||||||
|
sum+=inst.weight;
|
||||||
|
}
|
||||||
|
if(sum<=0)
|
||||||
|
sum=1f;
|
||||||
|
for(CatalogDefaultInstance inst:result){
|
||||||
|
inst.weight/=sum;
|
||||||
|
}
|
||||||
|
float rand=ThreadLocalRandom.current().nextFloat();
|
||||||
|
float prev=0f;
|
||||||
|
for(CatalogDefaultInstance inst:result){
|
||||||
|
if(rand>=prev && rand<prev+inst.weight){
|
||||||
|
setChosenDefaultServer(inst.domain);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prev+=inst.weight;
|
||||||
|
}
|
||||||
|
// Just in case something didn't add up
|
||||||
|
setChosenDefaultServer(result.get(result.size()-1).domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error){
|
||||||
|
setChosenDefaultServer(DEFAULT_SERVER);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.execNoAuth("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setChosenDefaultServer(String domain){
|
||||||
|
chosenDefaultServer=domain;
|
||||||
|
loadingDefaultServer=false;
|
||||||
|
if(defaultServerButton!=null && getActivity()!=null){
|
||||||
|
defaultServerButton.setTextVisible(true);
|
||||||
|
defaultServerProgress.setVisibility(View.GONE);
|
||||||
|
defaultServerButton.setText(getString(R.string.join_default_server, chosenDefaultServer));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.joinmastodon.android.model.catalog;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.AllFieldsAreRequired;
|
||||||
|
import org.joinmastodon.android.model.BaseModel;
|
||||||
|
|
||||||
|
@AllFieldsAreRequired
|
||||||
|
public class CatalogDefaultInstance extends BaseModel{
|
||||||
|
public String domain;
|
||||||
|
public float weight;
|
||||||
|
}
|
|
@ -104,14 +104,32 @@
|
||||||
android:layout_height="0px"
|
android:layout_height="0px"
|
||||||
android:layout_weight="1"/>
|
android:layout_weight="1"/>
|
||||||
|
|
||||||
<Button
|
<FrameLayout
|
||||||
android:id="@+id/btn_join_default_server"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:layout_marginLeft="16dp"
|
|
||||||
android:layout_marginRight="16dp"
|
<org.joinmastodon.android.ui.views.ProgressBarButton
|
||||||
style="@style/Widget.Mastodon.M3.Button.Filled"
|
android:id="@+id/btn_join_default_server"
|
||||||
tools:text="@string/join_default_server"/>
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
style="@style/Widget.Mastodon.M3.Button.Filled"
|
||||||
|
tools:text="@string/join_default_server"/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/action_progress"
|
||||||
|
style="?android:progressBarStyleSmall"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:elevation="10dp"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:outlineProvider="none"
|
||||||
|
android:indeterminateTint="#FFF"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btn_get_started"
|
android:id="@+id/btn_get_started"
|
||||||
|
|
Loading…
Reference in New Issue