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

View File

@ -27,6 +27,12 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".InstancePickerActivity"
android:label="@string/instances_picker"
android:configChanges="orientation|screenSize|layoutDirection"
android:theme="@style/AppTheme"/>
</application>
</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 FrameLayout webview_container;
private ValueCallback<Uri[]> mFilePathCallback;
private static final int PICK_INSTANCE = 546;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -359,9 +360,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}).start());
//TODO: uncomment and add support for picking instances when available
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);
});*/
});
AlertDialog alert = alt_bld.create();
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 {
private String finalUrl;
private final String finalUrl;
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"?>
<!--
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"

View File

@ -1,4 +1,20 @@
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
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"?><!--
Copyright 2017 Thomas Schneider
<?xml version="1.0" encoding="utf-8"?>
<!--
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
GNU General Public License as published by the Free Software Foundation; either version 3 of the
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
Public License for more details.
You should have received a copy of the GNU General Public License along with Fedilab; if not,
see <http://www.gnu.org/licenses>
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"
xmlns:tools="http://schemas.android.com/tools"

View File

@ -1,4 +1,20 @@
<?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"
android:layout_width="match_parent"
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="permissions_message">This permission is used for searching events next to your location.</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>

View File

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