kopia lustrzana https://github.com/ryukoposting/Signal-Android
326 wiersze
12 KiB
Java
326 wiersze
12 KiB
Java
package org.thoughtcrime.securesms.logsubmit;
|
|
|
|
import android.app.Activity;
|
|
import android.content.Intent;
|
|
import android.net.Uri;
|
|
import android.os.Bundle;
|
|
import android.provider.DocumentsContract;
|
|
import android.text.SpannableString;
|
|
import android.text.Spanned;
|
|
import android.text.style.URLSpan;
|
|
import android.text.util.Linkify;
|
|
import android.view.Menu;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
import android.widget.TextView;
|
|
import android.widget.Toast;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.appcompat.app.AlertDialog;
|
|
import androidx.appcompat.widget.SearchView;
|
|
import androidx.core.app.ShareCompat;
|
|
import androidx.core.text.util.LinkifyCompat;
|
|
import androidx.lifecycle.ViewModelProvider;
|
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
import org.thoughtcrime.securesms.BaseActivity;
|
|
import org.thoughtcrime.securesms.R;
|
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
|
import org.thoughtcrime.securesms.util.LongClickCopySpan;
|
|
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
|
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
|
import org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton;
|
|
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
|
|
|
import java.util.List;
|
|
|
|
public class SubmitDebugLogActivity extends BaseActivity implements SubmitDebugLogAdapter.Listener {
|
|
|
|
private static final int CODE_SAVE = 24601;
|
|
|
|
private RecyclerView lineList;
|
|
private SubmitDebugLogAdapter adapter;
|
|
private SubmitDebugLogViewModel viewModel;
|
|
|
|
private View warningBanner;
|
|
private View editBanner;
|
|
private CircularProgressMaterialButton submitButton;
|
|
private AlertDialog loadingDialog;
|
|
private View scrollToBottomButton;
|
|
private View scrollToTopButton;
|
|
|
|
private MenuItem editMenuItem;
|
|
private MenuItem doneMenuItem;
|
|
private MenuItem searchMenuItem;
|
|
private MenuItem saveMenuItem;
|
|
|
|
private AlertDialog fileProgressDialog;
|
|
|
|
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
dynamicTheme.onCreate(this);
|
|
setContentView(R.layout.submit_debug_log_activity);
|
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
getSupportActionBar().setTitle(R.string.HelpSettingsFragment__debug_log);
|
|
|
|
this.viewModel = new ViewModelProvider(this, new SubmitDebugLogViewModel.Factory()).get(SubmitDebugLogViewModel.class);
|
|
|
|
initView();
|
|
initViewModel();
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
super.onResume();
|
|
dynamicTheme.onResume(this);
|
|
}
|
|
|
|
@Override
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
|
getMenuInflater().inflate(R.menu.submit_debug_log_normal, menu);
|
|
|
|
this.editMenuItem = menu.findItem(R.id.menu_edit_log);
|
|
this.doneMenuItem = menu.findItem(R.id.menu_done_editing_log);
|
|
this.searchMenuItem = menu.findItem(R.id.menu_search);
|
|
this.saveMenuItem = menu.findItem(R.id.menu_save);
|
|
|
|
SearchView searchView = (SearchView) searchMenuItem.getActionView();
|
|
SearchView.OnQueryTextListener queryListener = new SearchView.OnQueryTextListener() {
|
|
@Override
|
|
public boolean onQueryTextSubmit(String query) {
|
|
viewModel.onQueryUpdated(query);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onQueryTextChange(String query) {
|
|
viewModel.onQueryUpdated(query);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
searchMenuItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
|
|
@Override
|
|
public boolean onMenuItemActionExpand(MenuItem item) {
|
|
searchView.setOnQueryTextListener(queryListener);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onMenuItemActionCollapse(MenuItem item) {
|
|
searchView.setOnQueryTextListener(null);
|
|
viewModel.onSearchClosed();
|
|
return true;
|
|
}
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
|
super.onOptionsItemSelected(item);
|
|
|
|
if (item.getItemId() == android.R.id.home) {
|
|
finish();
|
|
return true;
|
|
} else if (item.getItemId() == R.id.menu_edit_log) {
|
|
viewModel.onEditButtonPressed();
|
|
} else if (item.getItemId() == R.id.menu_done_editing_log) {
|
|
viewModel.onDoneEditingButtonPressed();
|
|
} else if (item.getItemId() == R.id.menu_save) {
|
|
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
intent.setType("application/zip");
|
|
intent.putExtra(Intent.EXTRA_TITLE, "signal-log-" + System.currentTimeMillis() + ".zip");
|
|
|
|
startActivityForResult(intent, CODE_SAVE);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void onBackPressed() {
|
|
if (!viewModel.onBackPressed()) {
|
|
super.onBackPressed();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
|
super.onActivityResult(requestCode, resultCode, data);
|
|
|
|
if (requestCode == CODE_SAVE && resultCode == Activity.RESULT_OK) {
|
|
Uri uri = data != null ? data.getData() : null;
|
|
viewModel.onDiskSaveLocationReady(uri);
|
|
fileProgressDialog = SimpleProgressDialog.show(this);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onLogDeleted(@NonNull LogLine logLine) {
|
|
viewModel.onLogDeleted(logLine);
|
|
}
|
|
|
|
private void initView() {
|
|
this.lineList = findViewById(R.id.debug_log_lines);
|
|
this.warningBanner = findViewById(R.id.debug_log_warning_banner);
|
|
this.editBanner = findViewById(R.id.debug_log_edit_banner);
|
|
this.submitButton = findViewById(R.id.debug_log_submit_button);
|
|
this.scrollToBottomButton = findViewById(R.id.debug_log_scroll_to_bottom);
|
|
this.scrollToTopButton = findViewById(R.id.debug_log_scroll_to_top);
|
|
|
|
this.adapter = new SubmitDebugLogAdapter(this, viewModel.getPagingController());
|
|
|
|
this.lineList.setLayoutManager(new LinearLayoutManager(this));
|
|
this.lineList.setAdapter(adapter);
|
|
this.lineList.setItemAnimator(null);
|
|
|
|
submitButton.setOnClickListener(v -> onSubmitClicked());
|
|
|
|
scrollToBottomButton.setOnClickListener(v -> lineList.scrollToPosition(adapter.getItemCount() - 1));
|
|
scrollToTopButton.setOnClickListener(v -> lineList.scrollToPosition(0));
|
|
|
|
lineList.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
|
@Override
|
|
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
|
if (((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition() < adapter.getItemCount() - 10) {
|
|
scrollToBottomButton.setVisibility(View.VISIBLE);
|
|
} else {
|
|
scrollToBottomButton.setVisibility(View.GONE);
|
|
}
|
|
|
|
if (((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition() > 10) {
|
|
scrollToTopButton.setVisibility(View.VISIBLE);
|
|
} else {
|
|
scrollToTopButton.setVisibility(View.GONE);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.loadingDialog = SimpleProgressDialog.show(this);
|
|
}
|
|
|
|
private void initViewModel() {
|
|
viewModel.getLines().observe(this, this::presentLines);
|
|
viewModel.getMode().observe(this, this::presentMode);
|
|
viewModel.getEvents().observe(this, this::presentEvents);
|
|
}
|
|
|
|
private void presentLines(@NonNull List<LogLine> lines) {
|
|
if (loadingDialog != null && lines.size() > 0) {
|
|
loadingDialog.dismiss();
|
|
loadingDialog = null;
|
|
|
|
warningBanner.setVisibility(View.VISIBLE);
|
|
submitButton.setVisibility(View.VISIBLE);
|
|
}
|
|
|
|
adapter.submitList(lines);
|
|
}
|
|
|
|
private void presentMode(@NonNull SubmitDebugLogViewModel.Mode mode) {
|
|
switch (mode) {
|
|
case NORMAL:
|
|
editBanner.setVisibility(View.GONE);
|
|
adapter.setEditing(false);
|
|
saveMenuItem.setVisible(true);
|
|
// TODO [greyson][log] Not yet implemented
|
|
// editMenuItem.setVisible(true);
|
|
// doneMenuItem.setVisible(false);
|
|
// searchMenuItem.setVisible(true);
|
|
break;
|
|
case SUBMITTING:
|
|
editBanner.setVisibility(View.GONE);
|
|
adapter.setEditing(false);
|
|
editMenuItem.setVisible(false);
|
|
doneMenuItem.setVisible(false);
|
|
searchMenuItem.setVisible(false);
|
|
saveMenuItem.setVisible(false);
|
|
break;
|
|
case EDIT:
|
|
editBanner.setVisibility(View.VISIBLE);
|
|
adapter.setEditing(true);
|
|
editMenuItem.setVisible(false);
|
|
doneMenuItem.setVisible(true);
|
|
searchMenuItem.setVisible(true);
|
|
saveMenuItem.setVisible(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void presentEvents(@NonNull SubmitDebugLogViewModel.Event event) {
|
|
switch (event) {
|
|
case FILE_SAVE_SUCCESS:
|
|
Toast.makeText(this, R.string.SubmitDebugLogActivity_save_complete, Toast.LENGTH_SHORT).show();
|
|
if (fileProgressDialog != null) {
|
|
fileProgressDialog.dismiss();
|
|
fileProgressDialog = null;
|
|
}
|
|
break;
|
|
case FILE_SAVE_ERROR:
|
|
Toast.makeText(this, R.string.SubmitDebugLogActivity_failed_to_save, Toast.LENGTH_SHORT).show();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void presentResultDialog(@NonNull String url) {
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this)
|
|
.setTitle(R.string.SubmitDebugLogActivity_success)
|
|
.setCancelable(false)
|
|
.setNeutralButton(android.R.string.ok, (d, w) -> finish())
|
|
.setPositiveButton(R.string.SubmitDebugLogActivity_share, (d, w) -> {
|
|
ShareCompat.IntentBuilder.from(this)
|
|
.setText(url)
|
|
.setType("text/plain")
|
|
.setEmailTo(new String[] { "support@signal.org" })
|
|
.startChooser();
|
|
});
|
|
|
|
String dialogText = getResources().getString(R.string.SubmitDebugLogActivity_copy_this_url_and_add_it_to_your_issue, url);
|
|
SpannableString spannableDialogText = new SpannableString(dialogText);
|
|
TextView dialogView = new TextView(builder.getContext());
|
|
LongClickCopySpan longClickUrl = new LongClickCopySpan(url);
|
|
|
|
|
|
LinkifyCompat.addLinks(spannableDialogText, Linkify.WEB_URLS);
|
|
|
|
URLSpan[] spans = spannableDialogText.getSpans(0, spannableDialogText.length(), URLSpan.class);
|
|
for (URLSpan span : spans) {
|
|
int start = spannableDialogText.getSpanStart(span);
|
|
int end = spannableDialogText.getSpanEnd(span);
|
|
|
|
spannableDialogText.setSpan(longClickUrl, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
}
|
|
|
|
dialogView.setText(spannableDialogText);
|
|
dialogView.setMovementMethod(LongClickMovementMethod.getInstance(this));
|
|
|
|
ViewUtil.setPadding(dialogView, (int) ThemeUtil.getThemedDimen(this, R.attr.dialogPreferredPadding));
|
|
|
|
builder.setView(dialogView);
|
|
builder.show();
|
|
}
|
|
|
|
private void onSubmitClicked() {
|
|
submitButton.setSpinning();
|
|
|
|
viewModel.onSubmitClicked().observe(this, result -> {
|
|
if (result.isPresent()) {
|
|
presentResultDialog(result.get());
|
|
} else {
|
|
Toast.makeText(this, R.string.SubmitDebugLogActivity_failed_to_submit_logs, Toast.LENGTH_LONG).show();
|
|
}
|
|
|
|
submitButton.cancelSpinning();
|
|
});
|
|
}
|
|
}
|