1
0
mirror of https://framagit.org/tom79/mobilizon-android-app synced 2025-06-05 21:59:22 +02:00

Add instances picker

This commit is contained in:
Thomas
2020-10-27 12:06:50 +01:00
parent 11fec8c4ac
commit fe610b7ecb
20 changed files with 1006 additions and 11 deletions

View File

@@ -25,6 +25,10 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
buildFeatures {
viewBinding = true
}
lintOptions { lintOptions {
disable 'MissingTranslation' disable 'MissingTranslation'
checkReleaseBuilds false checkReleaseBuilds false
@@ -44,8 +48,8 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1' implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.2' implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
implementation 'androidx.navigation:navigation-fragment:2.3.0' implementation 'androidx.navigation:navigation-fragment:2.3.1'
implementation 'androidx.navigation:navigation-ui:2.3.0' implementation 'androidx.navigation:navigation-ui:2.3.1'
testImplementation 'junit:junit:4.13' testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

View File

@@ -27,6 +27,12 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".InstancePickerActivity"
android:label="@string/instances_picker"
android:configChanges="orientation|screenSize|layoutDirection"
android:theme="@style/AppTheme"/>
</application> </application>
</manifest> </manifest>

View File

@@ -0,0 +1,132 @@
package app.fedilab.mobilizon;
/* Copyright 2020 Thomas Schneider
*
* This file is a part of Mobilizon app
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
* see <http://www.gnu.org/licenses>. */
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import app.fedilab.mobilizon.client.entities.Search;
import app.fedilab.mobilizon.client.entities.data.InstanceData;
import app.fedilab.mobilizon.databinding.ActivityInstancePickerBinding;
import app.fedilab.mobilizon.drawer.InstanceAdapter;
import app.fedilab.mobilizon.viewmodel.SearchInstancesVM;
public class InstancePickerActivity extends AppCompatActivity {
private ActivityInstancePickerBinding binding;
private List<InstanceData.Instance> instances;
private boolean flag_loading;
private String max_id;
private Search search;
private InstanceAdapter instanceAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityInstancePickerBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
if (getSupportActionBar() != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
search = new Search();
search.setCount("10");
search.setStart(max_id);
search.setSort("-createdAt");
max_id = "0";
setContentView(R.layout.activity_instance_picker);
instances = new ArrayList<>();
binding.loader.setVisibility(View.VISIBLE);
flag_loading = true;
LinearLayoutManager mLayoutManager = new LinearLayoutManager(InstancePickerActivity.this);
SearchInstancesVM searchInstancesVM = new ViewModelProvider(InstancePickerActivity.this).get(SearchInstancesVM.class);
instanceAdapter = new InstanceAdapter(instances);
binding.lvInstances.setAdapter(instanceAdapter);
binding.lvInstances.setLayoutManager(mLayoutManager);
binding.lvInstances.addOnScrollListener(new RecyclerView.OnScrollListener() {
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (dy > 0) {
int visibleItemCount = mLayoutManager.getChildCount();
int totalItemCount = mLayoutManager.getItemCount();
if (firstVisibleItem + visibleItemCount == totalItemCount) {
if (!flag_loading) {
flag_loading = true;
search.setStart(max_id);
searchInstancesVM.get(search).observe(InstancePickerActivity.this, instanceData -> manageVIewInstance(instanceData));
binding.loadingNextInstances.setVisibility(View.VISIBLE);
}
} else {
binding.loadingNextInstances.setVisibility(View.GONE);
}
}
}
});
searchInstancesVM.get(search).observe(InstancePickerActivity.this, this::manageVIewInstance);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
public void manageVIewInstance(InstanceData instanceData) {
binding.loader.setVisibility(View.GONE);
binding.loadingNextInstances.setVisibility(View.GONE);
if (instanceData == null || instanceData.data.size() == 0) {
binding.noAction.setVisibility(View.VISIBLE);
binding.lvInstances.setVisibility(View.GONE);
return;
}
int oldPosition = this.instances.size();
List<InstanceData.Instance> instances = instanceData.data;
this.instances.addAll(instances);
instanceAdapter.notifyItemRangeInserted(oldPosition, instances.size());
binding.noAction.setVisibility(View.GONE);
binding.lvInstances.setVisibility(View.VISIBLE);
max_id = String.valueOf(Integer.parseInt(max_id) + 10);
}
}

View File

@@ -61,6 +61,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
private WebView main_webview; private WebView main_webview;
private FrameLayout webview_container; private FrameLayout webview_container;
private ValueCallback<Uri[]> mFilePathCallback; private ValueCallback<Uri[]> mFilePathCallback;
private static final int PICK_INSTANCE = 546;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@@ -359,9 +360,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}).start()); }).start());
//TODO: uncomment and add support for picking instances when available //TODO: uncomment and add support for picking instances when available
alt_bld.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); alt_bld.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
/*alt_bld.setNeutralButton(R.string.help, (dialog, which) -> { alt_bld.setNeutralButton(R.string.help, (dialog, which) -> {
Intent intent = new Intent(MainActivity.this, InstancePickerActivity.class);
startActivityForResult(intent, PICK_INSTANCE); startActivityForResult(intent, PICK_INSTANCE);
});*/ });
AlertDialog alert = alt_bld.create(); AlertDialog alert = alt_bld.create();
alert.show(); alert.show();
} }

View File

@@ -0,0 +1,31 @@
package app.fedilab.mobilizon.client;
/* Copyright 2020 Thomas Schneider
*
* This file is a part of Mobilizon app
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
* see <http://www.gnu.org/licenses>. */
import app.fedilab.mobilizon.client.entities.data.InstanceData;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
interface InstancesService {
@GET("instances")
Call<InstanceData> getInstances(
@Query("start") String maxId,
@Query("count") String count,
@Query("search") String search,
@Query("sort") String sort);
}

View File

@@ -0,0 +1,57 @@
package app.fedilab.mobilizon.client;
/* Copyright 2020 Thomas Schneider
*
* This file is a part of Mobilizon app
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
* see <http://www.gnu.org/licenses>. */
import java.io.IOException;
import app.fedilab.mobilizon.client.entities.Search;
import app.fedilab.mobilizon.client.entities.data.InstanceData;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitInstancesAPI {
private InstancesService init() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://instances.joinmobilizon.org/api/v1")
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(InstancesService.class);
}
/**
* Get NodeInfo
*
* @return APIResponse
*/
public InstanceData search(Search search) {
InstancesService instancesService = init();
try {
Call<InstanceData> instanceDataCall = instancesService.getInstances(search.getStart(), search.getCount(), search.getSearch(), search.getSort());
Response<InstanceData> response = instanceDataCall.execute();
if (response.isSuccessful() && response.body() != null) {
return response.body();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

View File

@@ -27,7 +27,7 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitMobilizonAPI { public class RetrofitMobilizonAPI {
private String finalUrl; private final String finalUrl;
public RetrofitMobilizonAPI(String instance) { public RetrofitMobilizonAPI(String instance) {

View File

@@ -0,0 +1,55 @@
package app.fedilab.mobilizon.client.entities;
/* Copyright 2020 Thomas Schneider
*
* This file is a part of Mobilizon app
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
* see <http://www.gnu.org/licenses>. */
public class Search {
private String start;
private String count;
private String search;
private String sort;
public String getStart() {
return start;
}
public void setStart(String start) {
this.start = start;
}
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
public String getSearch() {
return search;
}
public void setSearch(String search) {
this.search = search;
}
public String getSort() {
return sort;
}
public void setSort(String sort) {
this.sort = sort;
}
}

View File

@@ -0,0 +1,239 @@
package app.fedilab.mobilizon.client.entities.data;
/* Copyright 2020 Thomas Schneider
*
* This file is a part of Mobilizon app
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
* see <http://www.gnu.org/licenses>. */
import com.google.gson.annotations.SerializedName;
import java.util.Date;
import java.util.List;
@SuppressWarnings({"unused", "RedundantSuppression"})
public class InstanceData {
@SerializedName("total")
public int total;
@SerializedName("data")
public List<Instance> data;
public static class Instance {
@SerializedName("country")
private String country;
@SerializedName("createdAt")
private Date createdAt;
@SerializedName("health")
private int health;
@SerializedName("host")
private String host;
@SerializedName("id")
private String id;
@SerializedName("languages")
private List<Language> languages;
@SerializedName("name")
private String name;
@SerializedName("shortDescription")
private String shortDescription;
@SerializedName("signupAllowed")
private boolean signupAllowed;
@SerializedName("supportsIPv6")
private boolean supportsIPv6;
@SerializedName("totalEvents")
private int totalEvents;
@SerializedName("totalGroups")
private int totalGroups;
@SerializedName("totalInstanceFollowers")
private int totalInstanceFollowers;
@SerializedName("totalInstanceFollowing")
private int totalInstanceFollowing;
@SerializedName("totalLocalEvents")
private int totalLocalEvents;
@SerializedName("totalLocalGroups")
private int totalLocalGroups;
@SerializedName("totalUsers")
private int totalUsers;
@SerializedName("version")
private String version;
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Language> getLanguages() {
return languages;
}
public void setLanguages(List<Language> languages) {
this.languages = languages;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getShortDescription() {
return shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
public boolean isSignupAllowed() {
return signupAllowed;
}
public void setSignupAllowed(boolean signupAllowed) {
this.signupAllowed = signupAllowed;
}
public boolean isSupportsIPv6() {
return supportsIPv6;
}
public void setSupportsIPv6(boolean supportsIPv6) {
this.supportsIPv6 = supportsIPv6;
}
public int getTotalEvents() {
return totalEvents;
}
public void setTotalEvents(int totalEvents) {
this.totalEvents = totalEvents;
}
public int getTotalGroups() {
return totalGroups;
}
public void setTotalGroups(int totalGroups) {
this.totalGroups = totalGroups;
}
public int getTotalInstanceFollowers() {
return totalInstanceFollowers;
}
public void setTotalInstanceFollowers(int totalInstanceFollowers) {
this.totalInstanceFollowers = totalInstanceFollowers;
}
public int getTotalInstanceFollowing() {
return totalInstanceFollowing;
}
public void setTotalInstanceFollowing(int totalInstanceFollowing) {
this.totalInstanceFollowing = totalInstanceFollowing;
}
public int getTotalLocalEvents() {
return totalLocalEvents;
}
public void setTotalLocalEvents(int totalLocalEvents) {
this.totalLocalEvents = totalLocalEvents;
}
public int getTotalLocalGroups() {
return totalLocalGroups;
}
public void setTotalLocalGroups(int totalLocalGroups) {
this.totalLocalGroups = totalLocalGroups;
}
public int getTotalUsers() {
return totalUsers;
}
public void setTotalUsers(int totalUsers) {
this.totalUsers = totalUsers;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
public static class Language {
@SerializedName("displayName")
private String displayName;
@SerializedName("code")
private String code;
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
}

View File

@@ -0,0 +1,130 @@
package app.fedilab.mobilizon.drawer;
/* Copyright 2020 Thomas Schneider
*
* This file is a part of Mobilizon app
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
* see <http://www.gnu.org/licenses>. */
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
import app.fedilab.mobilizon.R;
import app.fedilab.mobilizon.client.entities.data.InstanceData;
import app.fedilab.mobilizon.client.entities.data.InstanceData.Instance;
import static android.app.Activity.RESULT_OK;
public class InstanceAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<Instance> instances;
private Context context;
public InstanceAdapter(List<Instance> instances) {
this.instances = instances;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
LayoutInflater layoutInflater = LayoutInflater.from(context);
return new ViewHolder(layoutInflater.inflate(R.layout.drawer_instance, parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
final Instance instance = instances.get(position);
final ViewHolder holder = (ViewHolder) viewHolder;
if (instance.getShortDescription() != null && instance.getShortDescription().trim().length() > 0) {
holder.description.setText(instance.getShortDescription());
holder.description.setVisibility(View.VISIBLE);
} else {
holder.description.setVisibility(View.GONE);
}
holder.name.setText(instance.getName());
holder.host.setText(instance.getHost());
holder.version.setText(instance.getVersion());
StringBuilder languages = new StringBuilder();
if (instance.getLanguages() != null && instance.getLanguages().size() > 0) {
for (InstanceData.Language language : instance.getLanguages()) {
languages.append(language.getDisplayName()).append(" ");
}
}
if (languages.toString().trim().length() == 0) {
holder.languages.setVisibility(View.GONE);
} else {
holder.languages.setText(languages);
holder.languages.setVisibility(View.VISIBLE);
}
holder.local_events.setText(context.getString(R.string.local_events, String.valueOf(instance.getTotalLocalEvents())));
holder.pickup.setOnClickListener(v -> {
Intent data = new Intent();
String instanceHost = instance.getHost();
data.setData(Uri.parse(instanceHost));
((Activity) context).setResult(RESULT_OK, data);
((Activity) context).finish();
});
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return instances.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
Button pickup;
TextView name, host, description;
TextView version, local_events, languages;
public ViewHolder(@NonNull View itemView) {
super(itemView);
pickup = itemView.findViewById(R.id.pickup);
name = itemView.findViewById(R.id.name);
host = itemView.findViewById(R.id.host);
description = itemView.findViewById(R.id.description);
local_events = itemView.findViewById(R.id.local_events);
version = itemView.findViewById(R.id.version);
languages = itemView.findViewById(R.id.languages);
}
}
}

View File

@@ -0,0 +1,56 @@
package app.fedilab.mobilizon.viewmodel;
/* Copyright 2020 Thomas Schneider
*
* This file is a part of Mobilizon app
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
* see <http://www.gnu.org/licenses>. */
import android.os.Handler;
import android.os.Looper;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import app.fedilab.mobilizon.client.RetrofitInstancesAPI;
import app.fedilab.mobilizon.client.entities.Search;
import app.fedilab.mobilizon.client.entities.data.InstanceData;
public class SearchInstancesVM extends ViewModel {
private MutableLiveData<InstanceData> instanceDataMutableLiveData;
public LiveData<InstanceData> get(Search search) {
instanceDataMutableLiveData = new MutableLiveData<>();
searchInstances(search);
return instanceDataMutableLiveData;
}
private void searchInstances(Search search) {
new Thread(() -> {
try {
RetrofitInstancesAPI retrofitInstancesAPI = new RetrofitInstancesAPI();
InstanceData instanceData = retrofitInstancesAPI.search(search);
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> instanceDataMutableLiveData.setValue(instanceData);
mainHandler.post(myRunnable);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}

View File

@@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="?attr/colorControlNormal" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M21,6h-2v9L6,15v2c0,0.55 0.45,1 1,1h11l4,4L22,7c0,-0.55 -0.45,-1 -1,-1zM17,12L17,3c0,-0.55 -0.45,-1 -1,-1L3,2c-0.55,0 -1,0.45 -1,1v14l4,-4h10c0.55,0 1,-0.45 1,-1z"/>
</vector>

View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020 Thomas Schneider
This file is a part of Mobilizon app
This program is free software; you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
see <http://www.gnu.org/licenses>.
-->
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/fab_margin">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".InstancePickerActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/fab_margin">
<androidx.cardview.widget.CardView
android:id="@+id/filters_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.SearchView
app:queryHint="@string/search_instance_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:animateLayoutChanges="false"
android:id="@+id/searchBar" />
</androidx.cardview.widget.CardView>
<!-- Main Loader -->
<RelativeLayout
android:id="@+id/loader"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/filters_container">
<com.github.ybq.android.spinkit.SpinKitView
style="@style/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:SpinKit_Color="?colorAccent" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/filters_container">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/lv_instances"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none" />
<RelativeLayout
android:id="@+id/no_action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:padding="10dp"
android:text="@string/no_results"
android:textSize="25sp" />
</RelativeLayout>
</LinearLayout>
<!-- Loader for next videos -->
<RelativeLayout
android:id="@+id/loading_next_instances"
android:layout_width="match_parent"
android:layout_height="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
>
<com.github.ybq.android.spinkit.SpinKitView
style="@style/progressBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:SpinKit_Color="?colorAccent" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.drawerlayout.widget.DrawerLayout>

View File

@@ -1,4 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020 Thomas Schneider
This file is a part of Mobilizon app
This program is free software; you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
see <http://www.gnu.org/licenses>.
-->
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"

View File

@@ -1,4 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020 Thomas Schneider
This file is a part of Mobilizon app
This program is free software; you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
see <http://www.gnu.org/licenses>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020 Thomas Schneider
This file is a part of Mobilizon app
This program is free software; you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
see <http://www.gnu.org/licenses>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:divider="?android:dividerHorizontal"
android:gravity="bottom"
android:orientation="vertical"
android:showDividers="end">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/host"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
app:layout_constraintStart_toEndOf="@+id/name"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/name" />
<TextView
android:id="@+id/version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description" />
<TextView
android:id="@+id/local_events"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:drawablePadding="10dp"
app:drawableStartCompat="@drawable/ic_baseline_group_24"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/version" />
<TextView
android:id="@+id/languages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:drawablePadding="10dp"
app:drawableStartCompat="@drawable/ic_baseline_forum_24"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/local_events" />
<Button
android:id="@+id/pickup"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="@string/pickup_instance"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/languages" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View File

@@ -1,18 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!-- <?xml version="1.0" encoding="utf-8"?>
Copyright 2017 Thomas Schneider <!--
Copyright 2020 Thomas Schneider
This file is a part of Fedilab This file is a part of Mobilizon app
This program is free software; you can redistribute it and/or modify it under the terms of the This program is free software; you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation; either version 3 of the GNU General Public License as published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version. License, or (at your option) any later version.
Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details. Public License for more details.
You should have received a copy of the GNU General Public License along with Fedilab; if not, You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
see <http://www.gnu.org/licenses> see <http://www.gnu.org/licenses>.
--> -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"

View File

@@ -1,4 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020 Thomas Schneider
This file is a part of Mobilizon app
This program is free software; you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
Mobilizon app is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along with Mobilizon app; if not,
see <http://www.gnu.org/licenses>.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -39,4 +39,9 @@
<string name="about_the_app">About the app (Release %1$s)</string> <string name="about_the_app">About the app (Release %1$s)</string>
<string name="permissions_message">This permission is used for searching events next to your location.</string> <string name="permissions_message">This permission is used for searching events next to your location.</string>
<string name="settings">Settings</string> <string name="settings">Settings</string>
<string name="search_instance_hint">Search among instances</string>
<string name="no_results">No results.</string>
<string name="instances_picker">Instances picker</string>
<string name="pickup_instance">Pick this instance</string>
<string name="local_events">Local events: %1$s</string>
</resources> </resources>

View File

@@ -16,4 +16,6 @@
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" /> <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<style name="progress" parent="SpinKitView.Circle" />
<style name="progressBottom" parent="SpinKitView.ThreeBounce" />
</resources> </resources>