New log activity
This commit is contained in:
parent
d43eea7ebe
commit
0549f37277
|
|
@ -16,7 +16,6 @@ import android.widget.Button;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
|
@ -24,6 +23,7 @@ import androidx.core.app.ActivityCompat;
|
|||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.meowcat.edxposed.manager.util.NavUtil;
|
||||
import org.meowcat.edxposed.manager.util.json.XposedTab;
|
||||
|
|
@ -206,7 +206,7 @@ public class BaseAdvancedInstaller extends Fragment {
|
|||
new Handler().postDelayed(() -> mClickedButton.performClick(), 500);
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(getActivity(), R.string.permissionNotGranted, Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(getActivity().findViewById(R.id.snackbar), R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package org.meowcat.edxposed.manager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
|
@ -14,12 +15,13 @@ import android.view.ViewGroup;
|
|||
import android.widget.ArrayAdapter;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.ListFragment;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.meowcat.edxposed.manager.repo.Module;
|
||||
import org.meowcat.edxposed.manager.repo.ModuleVersion;
|
||||
import org.meowcat.edxposed.manager.repo.ReleaseType;
|
||||
|
|
@ -40,6 +42,7 @@ import static org.meowcat.edxposed.manager.XposedApp.WRITE_EXTERNAL_PERMISSION;
|
|||
|
||||
public class DownloadDetailsVersionsFragment extends ListFragment {
|
||||
private DownloadDetailsActivity mActivity;
|
||||
private View rootView;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
|
|
@ -48,6 +51,7 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
|
|||
if (mActivity == null) {
|
||||
return;
|
||||
}
|
||||
rootView = mActivity.findViewById(R.id.snackbar);
|
||||
Module module = mActivity.getModule();
|
||||
if (module == null)
|
||||
return;
|
||||
|
|
@ -95,7 +99,7 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
|
|||
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
DownloadView.mClickedButton.performClick();
|
||||
} else {
|
||||
Toast.makeText(getActivity(), R.string.permissionNotGranted, Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(rootView, R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -120,7 +124,7 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
|
|||
@Override
|
||||
public void onDownloadFinished(Context context, DownloadsUtil.DownloadInfo info) {
|
||||
File localFile = new File(info.localFilename);
|
||||
|
||||
View rootView = ((Activity) context).findViewById(R.id.snackbar);
|
||||
if (!localFile.isFile())
|
||||
return;
|
||||
|
||||
|
|
@ -128,12 +132,12 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
|
|||
try {
|
||||
String actualMd5Sum = HashUtil.md5(localFile);
|
||||
if (!moduleVersion.md5sum.equals(actualMd5Sum)) {
|
||||
Toast.makeText(context, context.getString(R.string.download_md5sum_incorrect, actualMd5Sum, moduleVersion.md5sum), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(rootView, context.getString(R.string.download_md5sum_incorrect, actualMd5Sum, moduleVersion.md5sum), Snackbar.LENGTH_LONG).show();
|
||||
DownloadsUtil.removeById(context, info.id);
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(context, context.getString(R.string.download_could_not_read_file, e.getMessage()), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(rootView, context.getString(R.string.download_could_not_read_file, e.getMessage()), Snackbar.LENGTH_LONG).show();
|
||||
DownloadsUtil.removeById(context, info.id);
|
||||
return;
|
||||
}
|
||||
|
|
@ -143,13 +147,13 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
|
|||
PackageInfo packageInfo = pm.getPackageArchiveInfo(info.localFilename, 0);
|
||||
|
||||
if (packageInfo == null) {
|
||||
Toast.makeText(context, R.string.download_no_valid_apk, Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(rootView, R.string.download_no_valid_apk, Snackbar.LENGTH_LONG).show();
|
||||
DownloadsUtil.removeById(context, info.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packageInfo.packageName.equals(moduleVersion.module.packageName)) {
|
||||
Toast.makeText(context, context.getString(R.string.download_incorrect_package_name, packageInfo.packageName, moduleVersion.module.packageName), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(rootView, context.getString(R.string.download_incorrect_package_name, packageInfo.packageName, moduleVersion.module.packageName), Snackbar.LENGTH_LONG).show();
|
||||
DownloadsUtil.removeById(context, info.id);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,17 +7,17 @@ import android.content.Intent;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
|
@ -25,29 +25,33 @@ import androidx.appcompat.app.ActionBar;
|
|||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Objects;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class LogsActivity extends BaseActivity {
|
||||
private boolean errorLog = false;
|
||||
private boolean allLog = false;
|
||||
private File mFileErrorLog = new File(XposedApp.BASE_DIR + "log/error.log");
|
||||
private File mFileErrorLogOld = new File(
|
||||
XposedApp.BASE_DIR + "log/error.log.old");
|
||||
private File mFileErrorLogError = new File(XposedApp.BASE_DIR + "log/all.log");
|
||||
private File mFileErrorLogOldError = new File(XposedApp.BASE_DIR + "log/all.log.old");
|
||||
private TextView mTxtLog;
|
||||
private ScrollView mSVLog;
|
||||
private HorizontalScrollView mHSVLog;
|
||||
private File mFileAllLog = new File(XposedApp.BASE_DIR + "log/all.log");
|
||||
private File mFileAllLogOld = new File(XposedApp.BASE_DIR + "log/all.log.old");
|
||||
private MenuItem mClickedMenuItem = null;
|
||||
private LogsAdapter mAdapter;
|
||||
private RecyclerView mListView;
|
||||
private Handler handler = new Handler();
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
|
|
@ -61,10 +65,6 @@ public class LogsActivity extends BaseActivity {
|
|||
bar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
setupWindowInsets();
|
||||
mTxtLog = findViewById(R.id.txtLog);
|
||||
mTxtLog.setTextIsSelectable(true);
|
||||
mSVLog = findViewById(R.id.svLog);
|
||||
mHSVLog = findViewById(R.id.hsvLog);
|
||||
|
||||
if (!XposedApp.getPreferences().getBoolean("hide_logcat_warning", false)) {
|
||||
@SuppressLint("InflateParams") final View dontShowAgainView = getLayoutInflater().inflate(R.layout.dialog_install_warning, null);
|
||||
|
|
@ -83,6 +83,29 @@ public class LogsActivity extends BaseActivity {
|
|||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
mAdapter = new LogsAdapter();
|
||||
mListView = findViewById(R.id.recyclerView);
|
||||
mListView.setAdapter(mAdapter);
|
||||
mListView.setLayoutManager(new LinearLayoutManager(this));
|
||||
TabLayout tabLayout = findViewById(R.id.sliding_tabs);
|
||||
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
allLog = tab.getPosition() != 0;
|
||||
reloadErrorLog();
|
||||
scrollDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -101,17 +124,6 @@ public class LogsActivity extends BaseActivity {
|
|||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
mClickedMenuItem = item;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_logs:
|
||||
item.setChecked(true);
|
||||
errorLog = false;
|
||||
reloadErrorLog();
|
||||
break;
|
||||
case R.id.menu_logs_err:
|
||||
item.setChecked(true);
|
||||
errorLog = true;
|
||||
reloadErrorLog();
|
||||
scrollDown();
|
||||
break;
|
||||
case R.id.menu_scroll_top:
|
||||
scrollTop();
|
||||
break;
|
||||
|
|
@ -138,36 +150,32 @@ public class LogsActivity extends BaseActivity {
|
|||
}
|
||||
|
||||
private void scrollTop() {
|
||||
mSVLog.post(() -> mSVLog.scrollTo(0, 0));
|
||||
mHSVLog.post(() -> mHSVLog.scrollTo(0, 0));
|
||||
mListView.smoothScrollToPosition(0);
|
||||
}
|
||||
|
||||
private void scrollDown() {
|
||||
mSVLog.post(() -> mSVLog.scrollTo(0, mTxtLog.getHeight()));
|
||||
mHSVLog.post(() -> mHSVLog.scrollTo(0, 0));
|
||||
mListView.smoothScrollToPosition(mAdapter.getItemCount() - 1);
|
||||
}
|
||||
|
||||
private void reloadErrorLog() {
|
||||
new LogsReader().execute(errorLog ? mFileErrorLogError : mFileErrorLog);
|
||||
mSVLog.post(() -> mSVLog.scrollTo(0, mTxtLog.getHeight()));
|
||||
mHSVLog.post(() -> mHSVLog.scrollTo(0, 0));
|
||||
new LogsReader().execute(allLog ? mFileAllLog : mFileErrorLog);
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
try {
|
||||
new FileOutputStream(errorLog ? mFileErrorLogError : mFileErrorLog).close();
|
||||
(errorLog ? mFileErrorLogOldError : mFileErrorLogOld).delete();
|
||||
mTxtLog.setText(R.string.log_is_empty);
|
||||
Toast.makeText(this, R.string.logs_cleared,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
new FileOutputStream(allLog ? mFileAllLog : mFileErrorLog).close();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
(allLog ? mFileAllLogOld : mFileErrorLogOld).delete();
|
||||
mAdapter.setEmpty();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
||||
reloadErrorLog();
|
||||
} catch (IOException e) {
|
||||
Toast.makeText(this, getResources().getString(R.string.logs_clear_failed) + "n" + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_clear_failed) + "n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void send() {
|
||||
Uri uri = FileProvider.getUriForFile(this, "org.meowcat.edxposed.manager.fileprovider", errorLog ? mFileErrorLogError : mFileErrorLog);
|
||||
Uri uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", allLog ? mFileAllLog : mFileErrorLog);
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
|
|
@ -187,20 +195,20 @@ public class LogsActivity extends BaseActivity {
|
|||
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, R.string.permissionNotGranted, Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private void save() {
|
||||
if (ActivityCompat.checkSelfPermission(Objects.requireNonNull(this), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, XposedApp.WRITE_EXTERNAL_PERMISSION);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
Toast.makeText(this, R.string.sdcard_not_writable, Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.sdcard_not_writable, Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -214,7 +222,7 @@ public class LogsActivity extends BaseActivity {
|
|||
File targetFile = new File(XposedApp.createFolder(), filename);
|
||||
|
||||
try {
|
||||
FileInputStream in = new FileInputStream(errorLog ? mFileErrorLogError : mFileErrorLog);
|
||||
FileInputStream in = new FileInputStream(allLog ? mFileAllLog : mFileErrorLog);
|
||||
FileOutputStream out = new FileOutputStream(targetFile);
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
|
|
@ -224,93 +232,119 @@ public class LogsActivity extends BaseActivity {
|
|||
in.close();
|
||||
out.close();
|
||||
|
||||
Toast.makeText(this, targetFile.toString(),
|
||||
Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), targetFile.toString(), Snackbar.LENGTH_LONG).show();
|
||||
} catch (IOException e) {
|
||||
Toast.makeText(this, getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private class LogsReader extends AsyncTask<File, Integer, String> {
|
||||
|
||||
private static final int MAX_LOG_SIZE = 1000 * 1024; // 1000 KB
|
||||
private class LogsReader extends AsyncTask<File, Integer, ArrayList<String>> {
|
||||
private ProgressDialog mProgressDialog;
|
||||
|
||||
private long skipLargeFile(BufferedReader is, long length) throws IOException {
|
||||
if (length < MAX_LOG_SIZE)
|
||||
return 0;
|
||||
|
||||
long skipped = length - MAX_LOG_SIZE;
|
||||
long yetToSkip = skipped;
|
||||
do {
|
||||
yetToSkip -= is.skip(yetToSkip);
|
||||
} while (yetToSkip > 0);
|
||||
|
||||
int c;
|
||||
do {
|
||||
c = is.read();
|
||||
if (c == -1)
|
||||
break;
|
||||
skipped++;
|
||||
} while (c != '\n');
|
||||
|
||||
return skipped;
|
||||
|
||||
}
|
||||
private Runnable mRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mProgressDialog.show();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
mTxtLog.setText("");
|
||||
mProgressDialog = new ProgressDialog(LogsActivity.this);
|
||||
mProgressDialog.setMessage(getString(R.string.loading));
|
||||
mProgressDialog.setProgress(0);
|
||||
mProgressDialog.show();
|
||||
handler.postDelayed(mRunnable, 500);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(File... log) {
|
||||
protected ArrayList<String> doInBackground(File... log) {
|
||||
Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 2);
|
||||
|
||||
StringBuilder llog = new StringBuilder(15 * 10 * 1024);
|
||||
|
||||
if (XposedApp.getPreferences().getBoolean(
|
||||
"disable_verbose_log", false) && errorLog) {
|
||||
llog.append(LogsActivity.this.getResources().getString(R.string.logs_verbose_disabled));
|
||||
return llog.toString();
|
||||
ArrayList<String> logs = new ArrayList<>();
|
||||
if (XposedApp.getPreferences().getBoolean("disable_verbose_log", false) && allLog) {
|
||||
logs.add(LogsActivity.this.getResources().getString(R.string.logs_verbose_disabled));
|
||||
return logs;
|
||||
}
|
||||
try {
|
||||
File logfile = log[0];
|
||||
BufferedReader br;
|
||||
br = new BufferedReader(new FileReader(logfile));
|
||||
long skipped = skipLargeFile(br, logfile.length());
|
||||
if (skipped > 0) {
|
||||
llog.append(LogsActivity.this.getResources().getString(R.string.logs_too_long));
|
||||
llog.append("\n-----------------\n");
|
||||
try (Scanner scanner = new Scanner(logfile)) {
|
||||
while (scanner.hasNextLine()) {
|
||||
logs.add(scanner.nextLine());
|
||||
}
|
||||
}
|
||||
|
||||
char[] temp = new char[1024];
|
||||
int read;
|
||||
while ((read = br.read(temp)) > 0) {
|
||||
llog.append(temp, 0, read);
|
||||
}
|
||||
br.close();
|
||||
return logs;
|
||||
} catch (IOException e) {
|
||||
llog.append(LogsActivity.this.getResources().getString(R.string.logs_cannot_read));
|
||||
llog.append(e.getMessage());
|
||||
logs.add(LogsActivity.this.getResources().getString(R.string.logs_cannot_read));
|
||||
logs.addAll(Arrays.asList(e.getMessage().split("\n")));
|
||||
}
|
||||
|
||||
return llog.toString();
|
||||
return logs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String llog) {
|
||||
mProgressDialog.dismiss();
|
||||
mTxtLog.setText(llog);
|
||||
protected void onPostExecute(ArrayList<String> logs) {
|
||||
if (logs.size() == 0) {
|
||||
mAdapter.setEmpty();
|
||||
} else {
|
||||
mAdapter.setLogs(logs);
|
||||
}
|
||||
handler.removeCallbacks(mRunnable);//It loaded so fast that no need to show progress
|
||||
if (mProgressDialog.isShowing()){
|
||||
mProgressDialog.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (llog.length() == 0)
|
||||
mTxtLog.setText(R.string.log_is_empty);
|
||||
private class LogsAdapter extends RecyclerView.Adapter<LogsAdapter.ViewHolder> {
|
||||
ArrayList<String> logs = new ArrayList<>();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public LogsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_log, parent, false);
|
||||
return new LogsAdapter.ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull LogsAdapter.ViewHolder holder, int position) {
|
||||
TextView view = holder.textView;
|
||||
view.setText(logs.get(position));
|
||||
view.measure(0, 0);
|
||||
int desiredWidth = view.getMeasuredWidth();
|
||||
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
|
||||
layoutParams.width = desiredWidth;
|
||||
if (mListView.getWidth() < desiredWidth) {
|
||||
mListView.requestLayout();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setLogs(ArrayList<String> logs) {
|
||||
this.logs.clear();
|
||||
this.logs.addAll(logs);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
void setEmpty() {
|
||||
logs.clear();
|
||||
logs.add(getString(R.string.log_is_empty));
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return logs.size();
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView textView;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
textView = itemView.findViewById(R.id.log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import android.widget.Filter;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
|
|
@ -38,6 +37,8 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
|||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.meowcat.edxposed.manager.repo.Module;
|
||||
import org.meowcat.edxposed.manager.repo.ModuleVersion;
|
||||
import org.meowcat.edxposed.manager.repo.ReleaseType;
|
||||
|
|
@ -189,7 +190,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, R.string.permissionNotGranted, Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -212,7 +213,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
}
|
||||
|
||||
if (ModuleUtil.getInstance().getEnabledModules().isEmpty()) {
|
||||
Toast.makeText(this, getString(R.string.no_enabled_modules), Toast.LENGTH_SHORT).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.no_enabled_modules, Snackbar.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -230,21 +231,21 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
in.close();
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
Toast.makeText(this, getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
Toast.makeText(this, enabledModulesPath.toString(), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), enabledModulesPath.toString(), Snackbar.LENGTH_LONG).show();
|
||||
return true;
|
||||
case R.id.export_installed_modules:
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
Toast.makeText(this, R.string.sdcard_not_writable, Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.sdcard_not_writable, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
Map<String, ModuleUtil.InstalledModule> installedModules = ModuleUtil.getInstance().getModules();
|
||||
|
||||
if (installedModules.isEmpty()) {
|
||||
Toast.makeText(this, getString(R.string.no_installed_modules), Toast.LENGTH_SHORT).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.no_installed_modules, Snackbar.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -262,11 +263,11 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
|
||||
fileOut.close();
|
||||
} catch (IOException e) {
|
||||
Toast.makeText(this, getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
Toast.makeText(this, installedModulesPath.toString(), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), installedModulesPath.toString(), Snackbar.LENGTH_LONG).show();
|
||||
return true;
|
||||
case R.id.import_installed_modules:
|
||||
return importModules(installedModulesPath);
|
||||
|
|
@ -279,15 +280,14 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
|
||||
private boolean importModules(File path) {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
Toast.makeText(this, R.string.sdcard_not_writable, Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.sdcard_not_writable, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
InputStream ips = null;
|
||||
RepoLoader repoLoader = RepoLoader.getInstance();
|
||||
List<Module> list = new ArrayList<>();
|
||||
if (!path.exists()) {
|
||||
Toast.makeText(this, getString(R.string.no_backup_found),
|
||||
Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.no_backup_found, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
|
|
@ -297,8 +297,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
}
|
||||
|
||||
if (path.length() == 0) {
|
||||
Toast.makeText(this, R.string.file_is_empty,
|
||||
Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.file_is_empty, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -311,15 +310,15 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
Module m = repoLoader.getModule(line);
|
||||
|
||||
if (m == null) {
|
||||
Toast.makeText(this, getString(R.string.download_details_not_found,
|
||||
line), Toast.LENGTH_SHORT).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), getString(R.string.download_details_not_found,
|
||||
line), Snackbar.LENGTH_SHORT).show();
|
||||
} else {
|
||||
list.add(m);
|
||||
}
|
||||
}
|
||||
br.close();
|
||||
} catch (ActivityNotFoundException | IOException e) {
|
||||
Toast.makeText(this, e.toString(), Toast.LENGTH_SHORT).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), e.toString(), Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
for (final Module m : list) {
|
||||
|
|
@ -397,7 +396,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
if (launchIntent != null) {
|
||||
startActivity(launchIntent);
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.module_no_ui), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.module_no_ui, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
return true;
|
||||
|
||||
|
|
@ -473,7 +472,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
if (launchIntent != null) {
|
||||
startActivity(launchIntent);
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.module_no_ui), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.module_no_ui, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -485,7 +484,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
if (launchIntent != null) {
|
||||
startActivity(launchIntent);
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.module_no_ui), Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.module_no_ui, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<font
|
||||
android:font="@font/exo_regular"
|
||||
android:fontStyle="normal"
|
||||
android:fontWeight="400"
|
||||
app:font="@font/exo_regular"
|
||||
app:fontStyle="normal"
|
||||
app:fontWeight="400" />
|
||||
|
||||
<font
|
||||
android:font="@font/exo_regular_italic"
|
||||
android:fontStyle="italic"
|
||||
android:fontWeight="400"
|
||||
app:font="@font/exo_regular_italic"
|
||||
app:fontStyle="italic"
|
||||
app:fontWeight="400" />
|
||||
|
||||
<font
|
||||
android:font="@font/exo_bold"
|
||||
android:fontStyle="normal"
|
||||
android:fontWeight="500"
|
||||
app:font="@font/exo_bold"
|
||||
app:fontStyle="normal"
|
||||
app:fontWeight="500" />
|
||||
|
||||
<font
|
||||
android:font="@font/exo_bold_italic"
|
||||
android:fontStyle="italic"
|
||||
android:fontWeight="500"
|
||||
app:font="@font/exo_bold_italic"
|
||||
app:fontStyle="italic"
|
||||
app:fontWeight="500" />
|
||||
|
||||
</font-family>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,44 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:id="@+id/snackbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
tools:context=".LogsActivity">
|
||||
android:clipToPadding="false">
|
||||
|
||||
<include layout="@layout/appbar_layout" />
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/container"
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?colorActionBar"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/sliding_tabs"
|
||||
style="@style/Widget.MaterialComponents.TabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?colorActionBar"
|
||||
app:tabMode="fixed">
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/nav_item_logs_err" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/nav_item_logs" />
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/svLog"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="UselessParent">
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical" />
|
||||
</HorizontalScrollView>
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/hsvLog"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtLog"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:textIsSelectable="true" />
|
||||
</HorizontalScrollView>
|
||||
|
||||
</ScrollView>
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/log"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:text=""
|
||||
android:textAppearance="@style/AppearanceFoundation.Caption"
|
||||
android:textSize="10sp" />
|
||||
|
|
@ -1,25 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu 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">
|
||||
<item
|
||||
android:icon="@drawable/ic_bug"
|
||||
android:title="@string/Logs"
|
||||
app:showAsAction="always"
|
||||
tools:ignore="AlwaysShowAction">
|
||||
<menu>
|
||||
<group android:checkableBehavior="single">
|
||||
<item
|
||||
android:id="@+id/menu_logs"
|
||||
android:checked="true"
|
||||
android:title="@string/nav_item_logs" />
|
||||
<item
|
||||
android:id="@+id/menu_logs_err"
|
||||
android:title="@string/nav_item_logs_err" />
|
||||
</group>
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/menu_save"
|
||||
android:icon="@drawable/ic_save"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@
|
|||
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
|
||||
</style>
|
||||
|
||||
<style name="AppearanceFoundation.Caption" parent="TextAppearance.AppCompat.Caption">
|
||||
<item name="android:fontFamily">@font/exo</item>
|
||||
<item name="android:textColor">?attr/colorOnSurface</item>
|
||||
</style>
|
||||
|
||||
<style name="AppThemeMain" parent="AppTheme">
|
||||
<item name="colorPrimaryDark">@color/colorBackground</item>
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue