mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-20 12:09:45 +01:00
Add support for endless loading
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
b984eea07a
commit
aa8d058ef8
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Heavily copied from and influenced by
|
||||||
|
* https://github.com/davideas/FlexibleAdapter/wiki/5.x-%7C-On-Load-More#automatic-load-more.
|
||||||
|
* Author: David Steduto under Apache2 licence
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.adapters.items;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.nextcloud.talk.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
||||||
|
import eu.davidea.flexibleadapter.Payload;
|
||||||
|
import eu.davidea.flexibleadapter.helpers.AnimatorHelper;
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible;
|
||||||
|
import eu.davidea.viewholders.FlexibleViewHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Davide Steduto
|
||||||
|
* @since 22/04/2016
|
||||||
|
*/
|
||||||
|
public class ProgressItem extends AbstractFlexibleItem<ProgressItem.ProgressViewHolder> {
|
||||||
|
|
||||||
|
private StatusEnum status = StatusEnum.MORE_TO_LOAD;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return this == o;//The default implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatusEnum getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(StatusEnum status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLayoutRes() {
|
||||||
|
return R.layout.rv_item_progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ProgressViewHolder holder, int position, List<Object> payloads) {
|
||||||
|
Context context = holder.itemView.getContext();
|
||||||
|
holder.progressBar.setVisibility(View.GONE);
|
||||||
|
holder.progressMessage.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
if (!adapter.isEndlessScrollEnabled()) {
|
||||||
|
setStatus(StatusEnum.DISABLE_ENDLESS);
|
||||||
|
} else if (payloads.contains(Payload.NO_MORE_LOAD)) {
|
||||||
|
setStatus(StatusEnum.NO_MORE_LOAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.status) {
|
||||||
|
case NO_MORE_LOAD:
|
||||||
|
holder.progressMessage.setText(
|
||||||
|
context.getString(R.string.nc_no_more_load_retry));
|
||||||
|
// Reset to default status for next binding
|
||||||
|
setStatus(StatusEnum.MORE_TO_LOAD);
|
||||||
|
break;
|
||||||
|
case DISABLE_ENDLESS:
|
||||||
|
holder.progressMessage.setText(context.getString(R.string.nc_endless_disabled));
|
||||||
|
break;
|
||||||
|
case ON_CANCEL:
|
||||||
|
holder.progressMessage.setText(context.getString(R.string.nc_endless_cancel));
|
||||||
|
// Reset to default status for next binding
|
||||||
|
setStatus(StatusEnum.MORE_TO_LOAD);
|
||||||
|
break;
|
||||||
|
case ON_ERROR:
|
||||||
|
holder.progressMessage.setText(context.getString(R.string.nc_endless_error));
|
||||||
|
// Reset to default status for next binding
|
||||||
|
setStatus(StatusEnum.MORE_TO_LOAD);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
holder.progressBar.setVisibility(View.VISIBLE);
|
||||||
|
holder.progressMessage.setVisibility(View.GONE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProgressViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
|
||||||
|
return new ProgressViewHolder(view, adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class ProgressViewHolder extends FlexibleViewHolder {
|
||||||
|
|
||||||
|
@BindView(R.id.progress_bar)
|
||||||
|
ProgressBar progressBar;
|
||||||
|
@BindView(R.id.progress_message)
|
||||||
|
TextView progressMessage;
|
||||||
|
|
||||||
|
ProgressViewHolder(View view, FlexibleAdapter adapter) {
|
||||||
|
super(view, adapter);
|
||||||
|
ButterKnife.bind(this, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scrollAnimators(@NonNull List<Animator> animators, int position, boolean isForward) {
|
||||||
|
AnimatorHelper.scaleAnimator(animators, itemView, 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum StatusEnum {
|
||||||
|
MORE_TO_LOAD, //Default = should have an empty Payload
|
||||||
|
DISABLE_ENDLESS, //Endless is disabled because user has set limits
|
||||||
|
NO_MORE_LOAD, //Non-empty Payload = Payload.NO_MORE_LOAD
|
||||||
|
ON_CANCEL,
|
||||||
|
ON_ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -66,8 +66,8 @@ public interface NcApi {
|
|||||||
Server URL is: baseUrl + ocsApiVersion + /apps/files_sharing/api/v1/sharees
|
Server URL is: baseUrl + ocsApiVersion + /apps/files_sharing/api/v1/sharees
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
Observable<ShareesOverall> getContactsWithSearchParam(@Header("Authorization") String authorization, @Url String url,
|
Observable<Response<ShareesOverall>> getContactsWithSearchParam(@Header("Authorization") String authorization, @Url String url,
|
||||||
@QueryMap Map<String, String> options);
|
@QueryMap Map<String, Object> options);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -52,6 +52,7 @@ import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
|
|||||||
import com.kennyc.bottomsheet.BottomSheet;
|
import com.kennyc.bottomsheet.BottomSheet;
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.activities.CallActivity;
|
import com.nextcloud.talk.activities.CallActivity;
|
||||||
|
import com.nextcloud.talk.adapters.items.ProgressItem;
|
||||||
import com.nextcloud.talk.adapters.items.UserHeaderItem;
|
import com.nextcloud.talk.adapters.items.UserHeaderItem;
|
||||||
import com.nextcloud.talk.adapters.items.UserItem;
|
import com.nextcloud.talk.adapters.items.UserItem;
|
||||||
import com.nextcloud.talk.api.NcApi;
|
import com.nextcloud.talk.api.NcApi;
|
||||||
@ -81,6 +82,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -101,10 +103,11 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
|
|||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import retrofit2.HttpException;
|
import retrofit2.HttpException;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication.class)
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
public class ContactsController extends BaseController implements SearchView.OnQueryTextListener,
|
public class ContactsController extends BaseController implements SearchView.OnQueryTextListener,
|
||||||
FlexibleAdapter.OnItemClickListener, FastScroller.OnScrollStateChangeListener {
|
FlexibleAdapter.OnItemClickListener, FastScroller.OnScrollStateChangeListener, FlexibleAdapter.EndlessScrollListener {
|
||||||
|
|
||||||
public static final String TAG = "ContactsController";
|
public static final String TAG = "ContactsController";
|
||||||
|
|
||||||
@ -144,6 +147,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
private List<AbstractFlexibleItem> contactItems = new ArrayList<>();
|
private List<AbstractFlexibleItem> contactItems = new ArrayList<>();
|
||||||
private BottomSheet bottomSheet;
|
private BottomSheet bottomSheet;
|
||||||
private View view;
|
private View view;
|
||||||
|
private int currentPage;
|
||||||
|
|
||||||
private SmoothScrollLinearLayoutManager layoutManager;
|
private SmoothScrollLinearLayoutManager layoutManager;
|
||||||
|
|
||||||
@ -156,6 +160,9 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
|
|
||||||
private HashMap<String, UserHeaderItem> userHeaderItems = new HashMap<>();
|
private HashMap<String, UserHeaderItem> userHeaderItems = new HashMap<>();
|
||||||
|
|
||||||
|
private boolean alreadyFetching = false;
|
||||||
|
private boolean canFetchFurther = true;
|
||||||
|
|
||||||
public ContactsController() {
|
public ContactsController() {
|
||||||
super();
|
super();
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
@ -213,13 +220,22 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
|
|
||||||
if (adapter == null) {
|
if (adapter == null) {
|
||||||
adapter = new FlexibleAdapter<>(contactItems, getActivity(), false);
|
adapter = new FlexibleAdapter<>(contactItems, getActivity(), false);
|
||||||
|
|
||||||
|
if (currentUser != null) {
|
||||||
|
fetchData(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setupAdapter();
|
||||||
|
prepareViews();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupAdapter() {
|
||||||
adapter.setNotifyChangeOfUnfilteredItems(true)
|
adapter.setNotifyChangeOfUnfilteredItems(true)
|
||||||
.setMode(SelectableAdapter.Mode.MULTI);
|
.setMode(SelectableAdapter.Mode.MULTI);
|
||||||
|
|
||||||
if (currentUser != null) {
|
adapter.setEndlessScrollListener(this, new ProgressItem());
|
||||||
fetchData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
adapter.setStickyHeaderElevation(5)
|
adapter.setStickyHeaderElevation(5)
|
||||||
.setUnlinkAllItemsOnRemoveHeaders(true)
|
.setUnlinkAllItemsOnRemoveHeaders(true)
|
||||||
@ -227,7 +243,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
.setStickyHeaders(true);
|
.setStickyHeaders(true);
|
||||||
|
|
||||||
adapter.addListener(this);
|
adapter.addListener(this);
|
||||||
prepareViews();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Optional
|
@Optional
|
||||||
@ -408,24 +423,50 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchData() {
|
private void fetchData(boolean startFromScratch) {
|
||||||
dispose(null);
|
dispose(null);
|
||||||
|
|
||||||
|
alreadyFetching = true;
|
||||||
Set<Sharee> shareeHashSet = new HashSet<>();
|
Set<Sharee> shareeHashSet = new HashSet<>();
|
||||||
|
|
||||||
|
if (startFromScratch) {
|
||||||
contactItems = new ArrayList<>();
|
contactItems = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
userHeaderItems = new HashMap<>();
|
userHeaderItems = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForContactsSearch(currentUser.getBaseUrl(),
|
RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForContactsSearch(currentUser.getBaseUrl(),
|
||||||
"");
|
"");
|
||||||
contactsQueryDisposable = ncApi.getContactsWithSearchParam(
|
|
||||||
|
int page = 1;
|
||||||
|
if (!startFromScratch) {
|
||||||
|
page = currentPage + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> modifiedQueryMap = new HashMap<>(retrofitBucket.getQueryMap());
|
||||||
|
modifiedQueryMap.put("page", page);
|
||||||
|
modifiedQueryMap.put("perPage", 100);
|
||||||
|
ncApi.getContactsWithSearchParam(
|
||||||
ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()),
|
ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()),
|
||||||
retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
|
retrofitBucket.getUrl(), modifiedQueryMap)
|
||||||
.subscribeOn(Schedulers.newThread())
|
.subscribeOn(Schedulers.newThread())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.retry(3)
|
.retry(3)
|
||||||
.subscribe((ShareesOverall shareesOverall) -> {
|
.subscribe(new Observer<Response>() {
|
||||||
if (shareesOverall != null) {
|
@Override
|
||||||
|
public void onSubscribe(Disposable d) {
|
||||||
|
contactsQueryDisposable = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(Response response) {
|
||||||
|
canFetchFurther = response.headers().size() > 0 &&
|
||||||
|
!TextUtils.isEmpty((response.headers().get("Link")));
|
||||||
|
if (response.body() != null) {
|
||||||
|
ShareesOverall shareesOverall = (ShareesOverall) response.body();
|
||||||
|
|
||||||
|
currentPage = (int) modifiedQueryMap.get("page");
|
||||||
|
|
||||||
if (shareesOverall.getOcs().getData().getUsers() != null) {
|
if (shareesOverall.getOcs().getData().getUsers() != null) {
|
||||||
shareeHashSet.addAll(shareesOverall.getOcs().getData().getUsers());
|
shareeHashSet.addAll(shareesOverall.getOcs().getData().getUsers());
|
||||||
@ -453,8 +494,14 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
}
|
}
|
||||||
|
|
||||||
participant.setUserId(sharee.getValue().getShareWith());
|
participant.setUserId(sharee.getValue().getShareWith());
|
||||||
contactItems.add(new UserItem(participant, currentUser,
|
|
||||||
userHeaderItems.get(headerTitle)));
|
UserItem newContactItem = new UserItem(participant, currentUser,
|
||||||
|
userHeaderItems.get(headerTitle));
|
||||||
|
|
||||||
|
if (!contactItems.contains(newContactItem)) {
|
||||||
|
contactItems.add(newContactItem);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -481,7 +528,15 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
return firstName.compareToIgnoreCase(secondName);
|
return firstName.compareToIgnoreCase(secondName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (startFromScratch) {
|
||||||
adapter.updateDataSet(contactItems, true);
|
adapter.updateDataSet(contactItems, true);
|
||||||
|
} else {
|
||||||
|
adapter.onLoadMoreComplete(null);
|
||||||
|
adapter = new FlexibleAdapter<>(contactItems, getActivity(), false);
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
setupAdapter();
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
searchItem.setVisible(contactItems.size() > 0);
|
searchItem.setVisible(contactItems.size() > 0);
|
||||||
swipeRefreshLayout.setRefreshing(false);
|
swipeRefreshLayout.setRefreshing(false);
|
||||||
|
|
||||||
@ -490,14 +545,16 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
checkAndHandleBottomButtons();
|
checkAndHandleBottomButtons();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}, throwable -> {
|
@Override
|
||||||
|
public void onError(Throwable e) {
|
||||||
if (searchItem != null) {
|
if (searchItem != null) {
|
||||||
searchItem.setVisible(false);
|
searchItem.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (throwable instanceof HttpException) {
|
if (e instanceof HttpException) {
|
||||||
HttpException exception = (HttpException) throwable;
|
HttpException exception = (HttpException) e;
|
||||||
switch (exception.code()) {
|
switch (exception.code()) {
|
||||||
case 401:
|
case 401:
|
||||||
if (getParentController() != null &&
|
if (getParentController() != null &&
|
||||||
@ -516,11 +573,18 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
|
|
||||||
swipeRefreshLayout.setRefreshing(false);
|
swipeRefreshLayout.setRefreshing(false);
|
||||||
dispose(contactsQueryDisposable);
|
dispose(contactsQueryDisposable);
|
||||||
|
|
||||||
}
|
}
|
||||||
, () -> {
|
|
||||||
|
@Override
|
||||||
|
public void onComplete() {
|
||||||
swipeRefreshLayout.setRefreshing(false);
|
swipeRefreshLayout.setRefreshing(false);
|
||||||
dispose(contactsQueryDisposable);
|
dispose(contactsQueryDisposable);
|
||||||
|
alreadyFetching = false;
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareViews() {
|
private void prepareViews() {
|
||||||
@ -529,7 +593,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
recyclerView.setHasFixedSize(true);
|
recyclerView.setHasFixedSize(true);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
swipeRefreshLayout.setOnRefreshListener(this::fetchData);
|
swipeRefreshLayout.setOnRefreshListener(() -> fetchData(true));
|
||||||
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
|
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
|
||||||
|
|
||||||
fastScroller.addOnScrollStateChangeListener(this);
|
fastScroller.addOnScrollStateChangeListener(this);
|
||||||
@ -538,8 +602,10 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
IFlexible abstractFlexibleItem = adapter.getItem(position);
|
IFlexible abstractFlexibleItem = adapter.getItem(position);
|
||||||
if (abstractFlexibleItem instanceof UserItem) {
|
if (abstractFlexibleItem instanceof UserItem) {
|
||||||
return ((UserItem) adapter.getItem(position)).getHeader().getModel();
|
return ((UserItem) adapter.getItem(position)).getHeader().getModel();
|
||||||
} else {
|
} else if (abstractFlexibleItem instanceof UserHeaderItem) {
|
||||||
return ((UserHeaderItem) adapter.getItem(position)).getModel();
|
return ((UserHeaderItem) adapter.getItem(position)).getModel();
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -779,4 +845,22 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
|||||||
secondaryRelativeLayout.setVisibility(View.VISIBLE);
|
secondaryRelativeLayout.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void noMoreLoad(int newItemsSize) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadMore(int lastPosition, int currentPage) {
|
||||||
|
if (adapter.hasFilter()) {
|
||||||
|
adapter.onLoadMoreComplete(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alreadyFetching && canFetchFurther) {
|
||||||
|
fetchData(false);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ public class ApiUtils {
|
|||||||
|
|
||||||
queryMap.put("format", "json");
|
queryMap.put("format", "json");
|
||||||
queryMap.put("search", searchQuery);
|
queryMap.put("search", searchQuery);
|
||||||
queryMap.put("perPage", "200");
|
|
||||||
queryMap.put("itemType", "call");
|
queryMap.put("itemType", "call");
|
||||||
|
|
||||||
retrofitBucket.setQueryMap(queryMap);
|
retrofitBucket.setQueryMap(queryMap);
|
||||||
|
45
app/src/main/res/layout/rv_item_progress.xml
Normal file
45
app/src/main/res/layout/rv_item_progress.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Nextcloud Talk application
|
||||||
|
~
|
||||||
|
~ @author Mario Danic
|
||||||
|
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
~
|
||||||
|
~ 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.
|
||||||
|
~
|
||||||
|
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/progress_message"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/nc_no_more_load_retry"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
@ -175,4 +175,10 @@ Find Nextcloud on https://nextcloud.com</string>
|
|||||||
<string name="nc_conversation_menu_video_call">Video call</string>
|
<string name="nc_conversation_menu_video_call">Video call</string>
|
||||||
<string name="nc_new_messages">New messages</string>
|
<string name="nc_new_messages">New messages</string>
|
||||||
|
|
||||||
|
<!-- Contacts endless loading -->
|
||||||
|
<string name="nc_no_more_load_retry">No more items to load. Refresh to retry.</string>
|
||||||
|
<string name="nc_endless_disabled">No more items to load (max reached).</string>
|
||||||
|
<string name="nc_endless_cancel">Cancelled by the user.</string>
|
||||||
|
<string name="nc_endless_error">An error occurred while loading more items.</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user