[app] Add empty view to lists (#575)
This commit is contained in:
parent
c13f4c90d1
commit
693016ae85
|
|
@ -71,6 +71,8 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
|
||||
import rikka.core.os.FileUtils;
|
||||
import rikka.core.res.ResourcesKt;
|
||||
import rikka.insets.WindowInsetsHelperKt;
|
||||
import rikka.recyclerview.RecyclerViewKt;
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
|
|
@ -132,16 +134,15 @@ public class LogsActivity extends BaseActivity {
|
|||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
if (!ConfigManager.isVerboseLogEnabled()) {
|
||||
WindowInsetsHelperKt.setInitialPadding(binding.recyclerView, 0, ResourcesKt.resolveDimensionPixelOffset(getTheme(), R.attr.actionBarSize, 0), 0, 0);
|
||||
binding.slidingTabs.setVisibility(View.GONE);
|
||||
}
|
||||
adapter = new LogsAdapter();
|
||||
RecyclerViewKt.fixEdgeEffect(binding.recyclerView, false, true);
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
layoutManager = new LinearLayoutManagerFix(this);
|
||||
binding.recyclerView.setLayoutManager(layoutManager);
|
||||
if (!ConfigManager.isVerboseLogEnabled()) {
|
||||
binding.slidingTabs.setVisibility(View.GONE);
|
||||
} else {
|
||||
RecyclerViewKt.addVerticalPadding(binding.recyclerView, 48, 0);
|
||||
}
|
||||
binding.slidingTabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
|
|
@ -224,7 +225,6 @@ public class LogsActivity extends BaseActivity {
|
|||
|
||||
private void clear() {
|
||||
if (ConfigManager.clearLogs(verbose)) {
|
||||
adapter.setEmpty();
|
||||
Snackbar.make(binding.snackbar, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
||||
reloadErrorLog();
|
||||
} else {
|
||||
|
|
@ -316,11 +316,8 @@ public class LogsActivity extends BaseActivity {
|
|||
|
||||
@Override
|
||||
protected void onPostExecute(List<String> logs) {
|
||||
if (logs.size() == 0) {
|
||||
adapter.setEmpty();
|
||||
} else {
|
||||
adapter.setLogs(logs);
|
||||
}
|
||||
adapter.setLogs(logs);
|
||||
|
||||
handler.removeCallbacks(mRunnable);//It loaded so fast that no need to show progress
|
||||
if (mProgressDialog.isShowing()) {
|
||||
mProgressDialog.dismiss();
|
||||
|
|
@ -349,7 +346,6 @@ public class LogsActivity extends BaseActivity {
|
|||
if (binding.recyclerView.getWidth() < desiredWidth) {
|
||||
binding.recyclerView.requestLayout();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setLogs(List<String> logs) {
|
||||
|
|
@ -358,12 +354,6 @@ public class LogsActivity extends BaseActivity {
|
|||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
void setEmpty() {
|
||||
logs.clear();
|
||||
logs.add(getString(R.string.log_is_empty));
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return logs.size();
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ import org.lsposed.manager.databinding.ActivityModuleDetailBinding;
|
|||
import org.lsposed.manager.databinding.ItemRepoRecyclerviewBinding;
|
||||
import org.lsposed.manager.repo.RepoLoader;
|
||||
import org.lsposed.manager.ui.activity.base.BaseActivity;
|
||||
import org.lsposed.manager.ui.widget.EmptyStateRecyclerView;
|
||||
import org.lsposed.manager.util.GlideApp;
|
||||
import org.lsposed.manager.util.LinearLayoutManagerFix;
|
||||
import org.lsposed.manager.util.ModuleUtil;
|
||||
|
|
@ -211,14 +212,18 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
|
||||
@Override
|
||||
public void onSingleInstalledModuleReloaded() {
|
||||
adapters.forEach(ModuleAdapter::refresh);
|
||||
adapters.forEach(adapter -> {
|
||||
adapter.refresh(true);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.menu_refresh) {
|
||||
adapters.forEach(ModuleAdapter::refresh);
|
||||
adapters.forEach(adapter -> {
|
||||
adapter.refresh(true);
|
||||
});
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
|
@ -322,10 +327,11 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
}
|
||||
}
|
||||
|
||||
private class ModuleAdapter extends RecyclerView.Adapter<ModuleAdapter.ViewHolder> implements Filterable {
|
||||
private class ModuleAdapter extends EmptyStateRecyclerView.EmptyStateAdapter<ModuleAdapter.ViewHolder> implements Filterable {
|
||||
private final List<ModuleUtil.InstalledModule> searchList = new ArrayList<>();
|
||||
private final List<ModuleUtil.InstalledModule> showList = new ArrayList<>();
|
||||
private final int userId;
|
||||
private boolean isLoaded;
|
||||
|
||||
ModuleAdapter(int userId) {
|
||||
this.userId = userId;
|
||||
|
|
@ -470,6 +476,11 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
View root;
|
||||
ImageView appIcon;
|
||||
|
|
@ -522,6 +533,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
showList.clear();
|
||||
//noinspection unchecked
|
||||
showList.addAll((List<ModuleUtil.InstalledModule>) results.values);
|
||||
isLoaded = true;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
package org.lsposed.manager.ui.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.text.Layout;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.lsposed.manager.R;
|
||||
|
||||
import rikka.core.res.ResourcesKt;
|
||||
import rikka.widget.borderview.BorderRecyclerView;
|
||||
|
||||
public class EmptyStateRecyclerView extends BorderRecyclerView {
|
||||
private final TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
||||
private final String emptyText;
|
||||
private final AdapterDataObserver emptyObserver = new AdapterDataObserver() {
|
||||
|
||||
@Override
|
||||
public void onChanged() {
|
||||
Adapter<?> adapter = getAdapter();
|
||||
if (adapter != null) {
|
||||
boolean newEmpty = adapter.getItemCount() == 0;
|
||||
if (empty != newEmpty) {
|
||||
empty = newEmpty;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private boolean empty = false;
|
||||
|
||||
|
||||
public EmptyStateRecyclerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public EmptyStateRecyclerView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public EmptyStateRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
|
||||
paint.setColor(ResourcesKt.resolveColor(context.getTheme(), android.R.attr.textColorSecondary));
|
||||
paint.setTextSize(16f * dm.scaledDensity);
|
||||
|
||||
emptyText = context.getString(R.string.list_empty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdapter(Adapter adapter) {
|
||||
var oldAdapter = getAdapter();
|
||||
if (oldAdapter != null) {
|
||||
oldAdapter.unregisterAdapterDataObserver(emptyObserver);
|
||||
}
|
||||
super.setAdapter(adapter);
|
||||
if (adapter != null) {
|
||||
adapter.registerAdapterDataObserver(emptyObserver);
|
||||
if (adapter instanceof EmptyStateAdapter && ((EmptyStateAdapter<?>) adapter).isLoaded()) {
|
||||
emptyObserver.onChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
super.dispatchDraw(canvas);
|
||||
|
||||
if (empty) {
|
||||
final int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
|
||||
final int height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
|
||||
|
||||
var textLayout = new StaticLayout(emptyText, paint, width, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(getPaddingLeft(), (height >> 1) + getPaddingTop() - (textLayout.getHeight() >> 1));
|
||||
|
||||
textLayout.draw(canvas);
|
||||
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract static class EmptyStateAdapter<T extends ViewHolder> extends Adapter<T> {
|
||||
abstract public boolean isLoaded();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:id="@+id/swipeRefreshLayout">
|
||||
|
||||
<rikka.widget.borderview.BorderRecyclerView
|
||||
<org.lsposed.manager.ui.widget.EmptyStateRecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
|
@ -83,4 +83,4 @@
|
|||
app:fitSystemWindowsInsets="bottom" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
</LinearLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
android:layout_marginTop="?actionBarSize"
|
||||
app:layout_fitSystemWindowsInsets="top" />
|
||||
|
||||
<rikka.widget.borderview.BorderRecyclerView
|
||||
<org.lsposed.manager.ui.widget.EmptyStateRecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
|
@ -64,4 +64,4 @@
|
|||
app:borderTopDrawable="@null"
|
||||
app:borderBottomVisibility="never"
|
||||
app:fitSystemWindowsInsets="top|bottom" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
|||
|
|
@ -71,14 +71,15 @@
|
|||
android:id="@+id/horizontalScrollView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:scrollbars="none">
|
||||
|
||||
<rikka.widget.borderview.BorderRecyclerView
|
||||
<org.lsposed.manager.ui.widget.EmptyStateRecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="?actionBarSize"
|
||||
android:paddingTop="104dp"
|
||||
app:borderTopVisibility="whenTop"
|
||||
app:borderTopDrawable="@null"
|
||||
app:borderBottomVisibility="never"
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
~ Copyright (C) 2021 LSPosed Contributors
|
||||
-->
|
||||
|
||||
<rikka.widget.borderview.BorderRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<org.lsposed.manager.ui.widget.EmptyStateRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -28,4 +28,4 @@
|
|||
app:borderTopVisibility="whenTop"
|
||||
app:borderTopDrawable="@null"
|
||||
app:borderBottomVisibility="never"
|
||||
app:fitSystemWindowsInsets="top|bottom" />
|
||||
app:fitSystemWindowsInsets="top|bottom" />
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@
|
|||
<string name="module_uninstall_message">要卸载此模块吗?</string>
|
||||
<string name="module_uninstalled">已卸载%1$s</string>
|
||||
<string name="module_uninstall_failed">卸载失败</string>
|
||||
<string name="user_title">用户 %d</string>
|
||||
|
||||
<!-- AppListActivity -->
|
||||
<string name="compile_speed">重新优化</string>
|
||||
|
|
@ -177,4 +178,5 @@
|
|||
<string name="NotInstallDetail">LSPosed 未安装</string>
|
||||
<string name="translators"><![CDATA[<a href="https://github.com/LSPosed/LSPosed">LSPosed</a>]]></string>
|
||||
<string name="copy_toast_msg">已复制</string>
|
||||
<string name="list_empty">¯\\\\_(ツ)_\/¯\n空空如也</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -179,4 +179,5 @@
|
|||
<string name="NotInstallDetail">LSPosed is not Installed</string>
|
||||
<string name="translators"><![CDATA[<a href="https://github.com/LSPosed/LSPosed">LSPosed</a>]]></string>
|
||||
<string name="copy_toast_msg">Copied</string>
|
||||
<string name="list_empty">¯\\\\_(ツ)_\/¯\nNothing here</string>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Reference in New Issue