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.ImageView;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
@ -24,6 +23,7 @@ import androidx.core.app.ActivityCompat;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
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.NavUtil;
|
||||||
import org.meowcat.edxposed.manager.util.json.XposedTab;
|
import org.meowcat.edxposed.manager.util.json.XposedTab;
|
||||||
|
|
@ -206,7 +206,7 @@ public class BaseAdvancedInstaller extends Fragment {
|
||||||
new Handler().postDelayed(() -> mClickedButton.performClick(), 500);
|
new Handler().postDelayed(() -> mClickedButton.performClick(), 500);
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
package org.meowcat.edxposed.manager;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
|
@ -14,12 +15,13 @@ import android.view.ViewGroup;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.fragment.app.ListFragment;
|
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.Module;
|
||||||
import org.meowcat.edxposed.manager.repo.ModuleVersion;
|
import org.meowcat.edxposed.manager.repo.ModuleVersion;
|
||||||
import org.meowcat.edxposed.manager.repo.ReleaseType;
|
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 {
|
public class DownloadDetailsVersionsFragment extends ListFragment {
|
||||||
private DownloadDetailsActivity mActivity;
|
private DownloadDetailsActivity mActivity;
|
||||||
|
private View rootView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
|
|
@ -48,6 +51,7 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
|
||||||
if (mActivity == null) {
|
if (mActivity == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
rootView = mActivity.findViewById(R.id.snackbar);
|
||||||
Module module = mActivity.getModule();
|
Module module = mActivity.getModule();
|
||||||
if (module == null)
|
if (module == null)
|
||||||
return;
|
return;
|
||||||
|
|
@ -95,7 +99,7 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
|
||||||
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
DownloadView.mClickedButton.performClick();
|
DownloadView.mClickedButton.performClick();
|
||||||
} else {
|
} 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
|
@Override
|
||||||
public void onDownloadFinished(Context context, DownloadsUtil.DownloadInfo info) {
|
public void onDownloadFinished(Context context, DownloadsUtil.DownloadInfo info) {
|
||||||
File localFile = new File(info.localFilename);
|
File localFile = new File(info.localFilename);
|
||||||
|
View rootView = ((Activity) context).findViewById(R.id.snackbar);
|
||||||
if (!localFile.isFile())
|
if (!localFile.isFile())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -128,12 +132,12 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
|
||||||
try {
|
try {
|
||||||
String actualMd5Sum = HashUtil.md5(localFile);
|
String actualMd5Sum = HashUtil.md5(localFile);
|
||||||
if (!moduleVersion.md5sum.equals(actualMd5Sum)) {
|
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);
|
DownloadsUtil.removeById(context, info.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} 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);
|
DownloadsUtil.removeById(context, info.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -143,13 +147,13 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
|
||||||
PackageInfo packageInfo = pm.getPackageArchiveInfo(info.localFilename, 0);
|
PackageInfo packageInfo = pm.getPackageArchiveInfo(info.localFilename, 0);
|
||||||
|
|
||||||
if (packageInfo == null) {
|
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);
|
DownloadsUtil.removeById(context, info.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!packageInfo.packageName.equals(moduleVersion.module.packageName)) {
|
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);
|
DownloadsUtil.removeById(context, info.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,17 @@ import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.HorizontalScrollView;
|
|
||||||
import android.widget.ScrollView;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
@ -25,29 +25,33 @@ import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.FileProvider;
|
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.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.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Objects;
|
import java.util.Scanner;
|
||||||
|
|
||||||
public class LogsActivity extends BaseActivity {
|
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 mFileErrorLog = new File(XposedApp.BASE_DIR + "log/error.log");
|
||||||
private File mFileErrorLogOld = new File(
|
private File mFileErrorLogOld = new File(
|
||||||
XposedApp.BASE_DIR + "log/error.log.old");
|
XposedApp.BASE_DIR + "log/error.log.old");
|
||||||
private File mFileErrorLogError = new File(XposedApp.BASE_DIR + "log/all.log");
|
private File mFileAllLog = new File(XposedApp.BASE_DIR + "log/all.log");
|
||||||
private File mFileErrorLogOldError = new File(XposedApp.BASE_DIR + "log/all.log.old");
|
private File mFileAllLogOld = new File(XposedApp.BASE_DIR + "log/all.log.old");
|
||||||
private TextView mTxtLog;
|
|
||||||
private ScrollView mSVLog;
|
|
||||||
private HorizontalScrollView mHSVLog;
|
|
||||||
private MenuItem mClickedMenuItem = null;
|
private MenuItem mClickedMenuItem = null;
|
||||||
|
private LogsAdapter mAdapter;
|
||||||
|
private RecyclerView mListView;
|
||||||
|
private Handler handler = new Handler();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
|
@ -61,10 +65,6 @@ public class LogsActivity extends BaseActivity {
|
||||||
bar.setDisplayHomeAsUpEnabled(true);
|
bar.setDisplayHomeAsUpEnabled(true);
|
||||||
}
|
}
|
||||||
setupWindowInsets();
|
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)) {
|
if (!XposedApp.getPreferences().getBoolean("hide_logcat_warning", false)) {
|
||||||
@SuppressLint("InflateParams") final View dontShowAgainView = getLayoutInflater().inflate(R.layout.dialog_install_warning, null);
|
@SuppressLint("InflateParams") final View dontShowAgainView = getLayoutInflater().inflate(R.layout.dialog_install_warning, null);
|
||||||
|
|
@ -83,6 +83,29 @@ public class LogsActivity extends BaseActivity {
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.show();
|
.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
|
@Override
|
||||||
|
|
@ -101,17 +124,6 @@ public class LogsActivity extends BaseActivity {
|
||||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||||
mClickedMenuItem = item;
|
mClickedMenuItem = item;
|
||||||
switch (item.getItemId()) {
|
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:
|
case R.id.menu_scroll_top:
|
||||||
scrollTop();
|
scrollTop();
|
||||||
break;
|
break;
|
||||||
|
|
@ -138,36 +150,32 @@ public class LogsActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollTop() {
|
private void scrollTop() {
|
||||||
mSVLog.post(() -> mSVLog.scrollTo(0, 0));
|
mListView.smoothScrollToPosition(0);
|
||||||
mHSVLog.post(() -> mHSVLog.scrollTo(0, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollDown() {
|
private void scrollDown() {
|
||||||
mSVLog.post(() -> mSVLog.scrollTo(0, mTxtLog.getHeight()));
|
mListView.smoothScrollToPosition(mAdapter.getItemCount() - 1);
|
||||||
mHSVLog.post(() -> mHSVLog.scrollTo(0, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reloadErrorLog() {
|
private void reloadErrorLog() {
|
||||||
new LogsReader().execute(errorLog ? mFileErrorLogError : mFileErrorLog);
|
new LogsReader().execute(allLog ? mFileAllLog : mFileErrorLog);
|
||||||
mSVLog.post(() -> mSVLog.scrollTo(0, mTxtLog.getHeight()));
|
|
||||||
mHSVLog.post(() -> mHSVLog.scrollTo(0, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clear() {
|
private void clear() {
|
||||||
try {
|
try {
|
||||||
new FileOutputStream(errorLog ? mFileErrorLogError : mFileErrorLog).close();
|
new FileOutputStream(allLog ? mFileAllLog : mFileErrorLog).close();
|
||||||
(errorLog ? mFileErrorLogOldError : mFileErrorLogOld).delete();
|
//noinspection ResultOfMethodCallIgnored
|
||||||
mTxtLog.setText(R.string.log_is_empty);
|
(allLog ? mFileAllLogOld : mFileErrorLogOld).delete();
|
||||||
Toast.makeText(this, R.string.logs_cleared,
|
mAdapter.setEmpty();
|
||||||
Toast.LENGTH_SHORT).show();
|
Snackbar.make(findViewById(R.id.snackbar), R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
||||||
reloadErrorLog();
|
reloadErrorLog();
|
||||||
} catch (IOException e) {
|
} 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() {
|
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();
|
Intent sendIntent = new Intent();
|
||||||
sendIntent.setAction(Intent.ACTION_SEND);
|
sendIntent.setAction(Intent.ACTION_SEND);
|
||||||
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||||
|
|
@ -187,20 +195,20 @@ public class LogsActivity extends BaseActivity {
|
||||||
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
||||||
}
|
}
|
||||||
} else {
|
} 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")
|
@SuppressLint("DefaultLocale")
|
||||||
private void save() {
|
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);
|
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, XposedApp.WRITE_EXTERNAL_PERMISSION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,7 +222,7 @@ public class LogsActivity extends BaseActivity {
|
||||||
File targetFile = new File(XposedApp.createFolder(), filename);
|
File targetFile = new File(XposedApp.createFolder(), filename);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FileInputStream in = new FileInputStream(errorLog ? mFileErrorLogError : mFileErrorLog);
|
FileInputStream in = new FileInputStream(allLog ? mFileAllLog : mFileErrorLog);
|
||||||
FileOutputStream out = new FileOutputStream(targetFile);
|
FileOutputStream out = new FileOutputStream(targetFile);
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
int len;
|
int len;
|
||||||
|
|
@ -224,93 +232,119 @@ public class LogsActivity extends BaseActivity {
|
||||||
in.close();
|
in.close();
|
||||||
out.close();
|
out.close();
|
||||||
|
|
||||||
Toast.makeText(this, targetFile.toString(),
|
Snackbar.make(findViewById(R.id.snackbar), targetFile.toString(), Snackbar.LENGTH_LONG).show();
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
} catch (IOException e) {
|
} 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")
|
@SuppressLint("StaticFieldLeak")
|
||||||
private class LogsReader extends AsyncTask<File, Integer, String> {
|
private class LogsReader extends AsyncTask<File, Integer, ArrayList<String>> {
|
||||||
|
|
||||||
private static final int MAX_LOG_SIZE = 1000 * 1024; // 1000 KB
|
|
||||||
private ProgressDialog mProgressDialog;
|
private ProgressDialog mProgressDialog;
|
||||||
|
private Runnable mRunnable = new Runnable() {
|
||||||
private long skipLargeFile(BufferedReader is, long length) throws IOException {
|
@Override
|
||||||
if (length < MAX_LOG_SIZE)
|
public void run() {
|
||||||
return 0;
|
mProgressDialog.show();
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
mTxtLog.setText("");
|
|
||||||
mProgressDialog = new ProgressDialog(LogsActivity.this);
|
mProgressDialog = new ProgressDialog(LogsActivity.this);
|
||||||
mProgressDialog.setMessage(getString(R.string.loading));
|
mProgressDialog.setMessage(getString(R.string.loading));
|
||||||
mProgressDialog.setProgress(0);
|
mProgressDialog.setProgress(0);
|
||||||
mProgressDialog.show();
|
handler.postDelayed(mRunnable, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String doInBackground(File... log) {
|
protected ArrayList<String> doInBackground(File... log) {
|
||||||
Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 2);
|
Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 2);
|
||||||
|
|
||||||
StringBuilder llog = new StringBuilder(15 * 10 * 1024);
|
ArrayList<String> logs = new ArrayList<>();
|
||||||
|
if (XposedApp.getPreferences().getBoolean("disable_verbose_log", false) && allLog) {
|
||||||
if (XposedApp.getPreferences().getBoolean(
|
logs.add(LogsActivity.this.getResources().getString(R.string.logs_verbose_disabled));
|
||||||
"disable_verbose_log", false) && errorLog) {
|
return logs;
|
||||||
llog.append(LogsActivity.this.getResources().getString(R.string.logs_verbose_disabled));
|
|
||||||
return llog.toString();
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
File logfile = log[0];
|
File logfile = log[0];
|
||||||
BufferedReader br;
|
try (Scanner scanner = new Scanner(logfile)) {
|
||||||
br = new BufferedReader(new FileReader(logfile));
|
while (scanner.hasNextLine()) {
|
||||||
long skipped = skipLargeFile(br, logfile.length());
|
logs.add(scanner.nextLine());
|
||||||
if (skipped > 0) {
|
|
||||||
llog.append(LogsActivity.this.getResources().getString(R.string.logs_too_long));
|
|
||||||
llog.append("\n-----------------\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
} catch (IOException e) {
|
||||||
llog.append(LogsActivity.this.getResources().getString(R.string.logs_cannot_read));
|
logs.add(LogsActivity.this.getResources().getString(R.string.logs_cannot_read));
|
||||||
llog.append(e.getMessage());
|
logs.addAll(Arrays.asList(e.getMessage().split("\n")));
|
||||||
}
|
}
|
||||||
|
|
||||||
return llog.toString();
|
return logs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(String 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();
|
mProgressDialog.dismiss();
|
||||||
mTxtLog.setText(llog);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (llog.length() == 0)
|
private class LogsAdapter extends RecyclerView.Adapter<LogsAdapter.ViewHolder> {
|
||||||
mTxtLog.setText(R.string.log_is_empty);
|
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.ImageView;
|
||||||
import android.widget.Switch;
|
import android.widget.Switch;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
|
|
@ -38,6 +37,8 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
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.Module;
|
||||||
import org.meowcat.edxposed.manager.repo.ModuleVersion;
|
import org.meowcat.edxposed.manager.repo.ModuleVersion;
|
||||||
import org.meowcat.edxposed.manager.repo.ReleaseType;
|
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);
|
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
||||||
}
|
}
|
||||||
} else {
|
} 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()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,21 +231,21 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
in.close();
|
in.close();
|
||||||
out.close();
|
out.close();
|
||||||
} catch (IOException e) {
|
} 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;
|
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;
|
return true;
|
||||||
case R.id.export_installed_modules:
|
case R.id.export_installed_modules:
|
||||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
Map<String, ModuleUtil.InstalledModule> installedModules = ModuleUtil.getInstance().getModules();
|
Map<String, ModuleUtil.InstalledModule> installedModules = ModuleUtil.getInstance().getModules();
|
||||||
|
|
||||||
if (installedModules.isEmpty()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,11 +263,11 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
|
|
||||||
fileOut.close();
|
fileOut.close();
|
||||||
} catch (IOException e) {
|
} 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;
|
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;
|
return true;
|
||||||
case R.id.import_installed_modules:
|
case R.id.import_installed_modules:
|
||||||
return importModules(installedModulesPath);
|
return importModules(installedModulesPath);
|
||||||
|
|
@ -279,15 +280,14 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
|
|
||||||
private boolean importModules(File path) {
|
private boolean importModules(File path) {
|
||||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
InputStream ips = null;
|
InputStream ips = null;
|
||||||
RepoLoader repoLoader = RepoLoader.getInstance();
|
RepoLoader repoLoader = RepoLoader.getInstance();
|
||||||
List<Module> list = new ArrayList<>();
|
List<Module> list = new ArrayList<>();
|
||||||
if (!path.exists()) {
|
if (!path.exists()) {
|
||||||
Toast.makeText(this, getString(R.string.no_backup_found),
|
Snackbar.make(findViewById(R.id.snackbar), R.string.no_backup_found, Snackbar.LENGTH_LONG).show();
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
@ -297,8 +297,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.length() == 0) {
|
if (path.length() == 0) {
|
||||||
Toast.makeText(this, R.string.file_is_empty,
|
Snackbar.make(findViewById(R.id.snackbar), R.string.file_is_empty, Snackbar.LENGTH_LONG).show();
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -311,15 +310,15 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
Module m = repoLoader.getModule(line);
|
Module m = repoLoader.getModule(line);
|
||||||
|
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
Toast.makeText(this, getString(R.string.download_details_not_found,
|
Snackbar.make(findViewById(R.id.snackbar), getString(R.string.download_details_not_found,
|
||||||
line), Toast.LENGTH_SHORT).show();
|
line), Snackbar.LENGTH_SHORT).show();
|
||||||
} else {
|
} else {
|
||||||
list.add(m);
|
list.add(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
br.close();
|
br.close();
|
||||||
} catch (ActivityNotFoundException | IOException e) {
|
} 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) {
|
for (final Module m : list) {
|
||||||
|
|
@ -397,7 +396,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
if (launchIntent != null) {
|
if (launchIntent != null) {
|
||||||
startActivity(launchIntent);
|
startActivity(launchIntent);
|
||||||
} else {
|
} 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;
|
return true;
|
||||||
|
|
||||||
|
|
@ -473,7 +472,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
if (launchIntent != null) {
|
if (launchIntent != null) {
|
||||||
startActivity(launchIntent);
|
startActivity(launchIntent);
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
|
|
@ -485,7 +484,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
if (launchIntent != null) {
|
if (launchIntent != null) {
|
||||||
startActivity(launchIntent);
|
startActivity(launchIntent);
|
||||||
} else {
|
} 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"?>
|
<?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:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/snackbar"
|
android:id="@+id/snackbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false">
|
||||||
tools:context=".LogsActivity">
|
|
||||||
|
|
||||||
<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
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/container"
|
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_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginTop="?attr/actionBarSize"
|
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<ScrollView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/svLog"
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
tools:ignore="UselessParent">
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
<HorizontalScrollView
|
android:orientation="vertical" />
|
||||||
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>
|
</HorizontalScrollView>
|
||||||
|
|
||||||
</ScrollView>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
</RelativeLayout>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
@ -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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_save"
|
android:id="@+id/menu_save"
|
||||||
android:icon="@drawable/ic_save"
|
android:icon="@drawable/ic_save"
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@
|
||||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
|
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
|
||||||
</style>
|
</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">
|
<style name="AppThemeMain" parent="AppTheme">
|
||||||
<item name="colorPrimaryDark">@color/colorBackground</item>
|
<item name="colorPrimaryDark">@color/colorBackground</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue