use of com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException in project nextcloud-notes by stefan-niedermann.
the class MainActivity method onCreate.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainViewModel = new ViewModelProvider(this).get(MainViewModel.class);
categoryViewModel = new ViewModelProvider(this).get(CategoryViewModel.class);
CapabilitiesWorker.update(this);
binding = DrawerLayoutBinding.inflate(getLayoutInflater());
activityBinding = ActivityNotesListViewBinding.bind(binding.activityNotesListView.getRoot());
setContentView(binding.getRoot());
this.coordinatorLayout = binding.activityNotesListView.activityNotesListView;
this.swipeRefreshLayout = binding.activityNotesListView.swiperefreshlayout;
this.fabCreate = binding.activityNotesListView.fabCreate;
this.listView = binding.activityNotesListView.recyclerView;
gridView = isGridViewEnabled();
if (!gridView || isDarkThemeActive(this)) {
activityBinding.activityNotesListView.setBackgroundColor(ContextCompat.getColor(this, R.color.primary));
}
setupToolbars();
setupNavigationList();
setupNotesList();
mainViewModel.getAccountsCount().observe(this, (count) -> {
if (count == 0) {
startActivityForResult(new Intent(this, ImportAccountActivity.class), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT);
} else {
executor.submit(() -> {
try {
final var account = mainViewModel.getLocalAccountByAccountName(SingleAccountHelper.getCurrentSingleSignOnAccount(getApplicationContext()).name);
runOnUiThread(() -> mainViewModel.postCurrentAccount(account));
} catch (NextcloudFilesAppAccountNotFoundException e) {
// Verbose log output for https://github.com/stefan-niedermann/nextcloud-notes/issues/1256
runOnUiThread(() -> new AlertDialog.Builder(this).setTitle(NextcloudFilesAppAccountNotFoundException.class.getSimpleName()).setMessage(R.string.backup).setPositiveButton(R.string.simple_backup, (a, b) -> executor.submit(() -> {
final var modifiedNotes = new LinkedList<Note>();
for (final var account : mainViewModel.getAccounts()) {
modifiedNotes.addAll(mainViewModel.getLocalModifiedNotes(account.getId()));
}
if (modifiedNotes.size() == 1) {
final var note = modifiedNotes.get(0);
ShareUtil.openShareDialog(this, note.getTitle(), note.getContent());
} else {
ShareUtil.openShareDialog(this, getResources().getQuantityString(R.plurals.share_multiple, modifiedNotes.size(), modifiedNotes.size()), mainViewModel.collectNoteContents(modifiedNotes.stream().map(Note::getId).collect(Collectors.toList())));
}
})).setNegativeButton(R.string.simple_error, (a, b) -> {
final var ssoPreferences = AccountImporter.getSharedPreferences(getApplicationContext());
final var ssoPreferencesString = new StringBuilder().append("Current SSO account: ").append(ssoPreferences.getString("PREF_CURRENT_ACCOUNT_STRING", null)).append("\n").append("\n").append("SSO SharedPreferences: ").append("\n");
for (final var entry : ssoPreferences.getAll().entrySet()) {
ssoPreferencesString.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n");
}
ssoPreferencesString.append("\n").append("Available accounts in DB: ").append(TextUtils.join(", ", mainViewModel.getAccounts().stream().map(Account::getAccountName).collect(Collectors.toList())));
runOnUiThread(() -> ExceptionDialogFragment.newInstance(new RuntimeException(e.getMessage(), new RuntimeException(ssoPreferencesString.toString(), e))).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()));
}).show());
} catch (NoCurrentAccountSelectedException e) {
runOnUiThread(() -> ExceptionDialogFragment.newInstance(e).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()));
}
});
}
});
mainViewModel.hasMultipleAccountsConfigured().observe(this, hasMultipleAccountsConfigured -> canMoveNoteToAnotherAccounts = hasMultipleAccountsConfigured);
mainViewModel.getSyncStatus().observe(this, syncStatus -> swipeRefreshLayout.setRefreshing(syncStatus));
mainViewModel.getSyncErrors().observe(this, exceptions -> {
if (mainViewModel.containsNonInfrastructureRelatedItems(exceptions)) {
BrandedSnackbar.make(coordinatorLayout, R.string.error_synchronization, Snackbar.LENGTH_LONG).setAction(R.string.simple_more, v -> ExceptionDialogFragment.newInstance(exceptions).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName())).show();
}
});
mainViewModel.getSelectedCategory().observe(this, (selectedCategory) -> {
binding.activityNotesListView.emptyContentView.getRoot().setVisibility(GONE);
adapter.setShowCategory(selectedCategory.getType() == RECENT || selectedCategory.getType() == FAVORITES);
fabCreate.show();
switch(selectedCategory.getType()) {
case RECENT:
{
activityBinding.searchText.setText(getString(R.string.search_in_all));
break;
}
case FAVORITES:
{
activityBinding.searchText.setText(getString(R.string.search_in_category, getString(R.string.label_favorites)));
break;
}
case UNCATEGORIZED:
{
activityBinding.searchText.setText(getString(R.string.search_in_category, getString(R.string.action_uncategorized)));
break;
}
case DEFAULT_CATEGORY:
default:
{
final String category = selectedCategory.getCategory();
if (category == null) {
throw new IllegalStateException(NavigationCategory.class.getSimpleName() + " type is " + DEFAULT_CATEGORY + ", but category is null.");
}
activityBinding.searchText.setText(getString(R.string.search_in_category, NoteUtil.extendCategory(category)));
break;
}
}
fabCreate.setOnClickListener((View view) -> {
final var createIntent = new Intent(getApplicationContext(), EditNoteActivity.class);
createIntent.putExtra(EditNoteActivity.PARAM_CATEGORY, selectedCategory);
if (activityBinding.searchView.getQuery().length() > 0) {
createIntent.putExtra(EditNoteActivity.PARAM_CONTENT, activityBinding.searchView.getQuery().toString());
invalidateOptionsMenu();
}
startActivityForResult(createIntent, REQUEST_CODE_CREATE_NOTE);
});
});
mainViewModel.getNotesListLiveData().observe(this, notes -> {
// https://stackoverflow.com/a/37342327
itemTouchHelper.attachToRecyclerView(null);
itemTouchHelper.attachToRecyclerView(listView);
adapter.setItemList(notes);
binding.activityNotesListView.progressCircular.setVisibility(GONE);
binding.activityNotesListView.emptyContentView.getRoot().setVisibility(notes.size() > 0 ? GONE : VISIBLE);
// Remove deleted notes from the selection
if (tracker.hasSelection()) {
final var deletedNotes = new LinkedList<Long>();
for (final var id : tracker.getSelection()) {
if (notes.stream().filter(item -> !item.isSection()).map(item -> (Note) item).noneMatch(item -> item.getId() == id)) {
deletedNotes.add(id);
}
}
for (final var id : deletedNotes) {
tracker.deselect(id);
}
}
});
mainViewModel.getSearchTerm().observe(this, adapter::setHighlightSearchQuery);
mainViewModel.getCategorySortingMethodOfSelectedCategory().observe(this, methodOfCategory -> {
updateSortMethodIcon(methodOfCategory.second);
activityBinding.sortingMethod.setOnClickListener((v) -> {
if (methodOfCategory.first != null) {
var newMethod = methodOfCategory.second;
if (newMethod == CategorySortingMethod.SORT_LEXICOGRAPHICAL_ASC) {
newMethod = CategorySortingMethod.SORT_MODIFIED_DESC;
} else {
newMethod = CategorySortingMethod.SORT_LEXICOGRAPHICAL_ASC;
}
final var modifyLiveData = mainViewModel.modifyCategoryOrder(methodOfCategory.first, newMethod);
modifyLiveData.observe(this, (next) -> modifyLiveData.removeObservers(this));
}
});
});
mainViewModel.getNavigationCategories().observe(this, navigationItems -> this.adapterCategories.setItems(navigationItems));
mainViewModel.getCurrentAccount().observe(this, (nextAccount) -> {
fabCreate.hide();
Glide.with(this).load(nextAccount.getUrl() + "/index.php/avatar/" + Uri.encode(nextAccount.getUserName()) + "/64").placeholder(R.drawable.ic_account_circle_grey_24dp).error(R.drawable.ic_account_circle_grey_24dp).apply(RequestOptions.circleCropTransform()).into(activityBinding.launchAccountSwitcher);
mainViewModel.synchronizeNotes(nextAccount, new IResponseCallback<>() {
@Override
public void onSuccess(Void v) {
Log.d(TAG, "Successfully synchronized notes for " + nextAccount.getAccountName());
}
@Override
public void onError(@NonNull Throwable t) {
runOnUiThread(() -> {
if (t instanceof IntendedOfflineException) {
Log.i(TAG, "Capabilities and notes not updated because " + nextAccount.getAccountName() + " is offline by intention.");
} else if (t instanceof NetworkErrorException) {
BrandedSnackbar.make(coordinatorLayout, getString(R.string.error_sync, getString(R.string.error_no_network)), Snackbar.LENGTH_LONG).show();
} else {
BrandedSnackbar.make(coordinatorLayout, R.string.error_synchronization, Snackbar.LENGTH_LONG).setAction(R.string.simple_more, v -> ExceptionDialogFragment.newInstance(t).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName())).show();
}
});
}
});
fabCreate.show();
activityBinding.launchAccountSwitcher.setOnClickListener((v) -> AccountSwitcherDialog.newInstance(nextAccount.getId()).show(getSupportFragmentManager(), AccountSwitcherDialog.class.getSimpleName()));
if (menuAdapter == null) {
menuAdapter = new MenuAdapter(getApplicationContext(), nextAccount, REQUEST_CODE_SERVER_SETTINGS, (menuItem) -> {
@Nullable Integer resultCode = menuItem.getResultCode();
if (resultCode == null) {
startActivity(menuItem.getIntent());
} else {
startActivityForResult(menuItem.getIntent(), resultCode);
}
});
binding.navigationMenu.setAdapter(menuAdapter);
} else {
menuAdapter.updateAccount(this, nextAccount);
}
});
}
use of com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException in project nextcloud-notes by stefan-niedermann.
the class ManageAccountsActivity method onChangeNotesPath.
private void onChangeNotesPath(@NonNull Account localAccount) {
final var repository = NotesRepository.getInstance(getApplicationContext());
final var editText = new EditText(this);
final var wrapper = createDialogViewWrapper();
final var dialog = new BrandedAlertDialogBuilder(this).setTitle(R.string.settings_notes_path).setMessage(R.string.settings_notes_path_description).setView(wrapper).setNeutralButton(android.R.string.cancel, null).setPositiveButton(R.string.action_edit_save, (v, d) -> new Thread(() -> {
try {
final var putSettingsCall = repository.putServerSettings(AccountImporter.getSingleSignOnAccount(this, localAccount.getAccountName()), new NotesSettings(editText.getText().toString(), null), getPreferredApiVersion(localAccount.getApiVersion()));
putSettingsCall.enqueue(new Callback<>() {
@Override
public void onResponse(@NonNull Call<NotesSettings> call, @NonNull Response<NotesSettings> response) {
final var body = response.body();
if (response.isSuccessful() && body != null) {
runOnUiThread(() -> Toast.makeText(ManageAccountsActivity.this, getString(R.string.settings_notes_path_success, body.getNotesPath()), Toast.LENGTH_LONG).show());
} else {
runOnUiThread(() -> Toast.makeText(ManageAccountsActivity.this, getString(R.string.http_status_code, response.code()), Toast.LENGTH_LONG).show());
}
}
@Override
public void onFailure(@NonNull Call<NotesSettings> call, @NonNull Throwable t) {
runOnUiThread(() -> ExceptionDialogFragment.newInstance(t).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()));
}
});
} catch (NextcloudFilesAppAccountNotFoundException e) {
ExceptionDialogFragment.newInstance(e).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
}
}).start()).show();
try {
repository.getServerSettings(AccountImporter.getSingleSignOnAccount(this, localAccount.getAccountName()), getPreferredApiVersion(localAccount.getApiVersion())).enqueue(new Callback<>() {
@Override
public void onResponse(@NonNull Call<NotesSettings> call, @NonNull Response<NotesSettings> response) {
runOnUiThread(() -> {
final var body = response.body();
if (response.isSuccessful() && body != null) {
wrapper.removeAllViews();
final var editText = new EditText(ManageAccountsActivity.this);
editText.setText(body.getNotesPath());
wrapper.addView(editText);
} else {
dialog.dismiss();
ExceptionDialogFragment.newInstance(new NetworkErrorException(getString(R.string.http_status_code, response.code()))).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
}
});
}
@Override
public void onFailure(@NonNull Call<NotesSettings> call, @NonNull Throwable t) {
runOnUiThread(() -> {
dialog.dismiss();
ExceptionDialogFragment.newInstance(t).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
});
}
});
} catch (NextcloudFilesAppAccountNotFoundException e) {
dialog.dismiss();
ExceptionDialogFragment.newInstance(e).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
}
}
use of com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException in project nextcloud-notes by stefan-niedermann.
the class MainViewModel method synchronizeCapabilities.
/**
* Updates the network status if necessary and pulls the latest {@link Capabilities} of the given {@param localAccount}
*/
public void synchronizeCapabilities(@NonNull Account localAccount, @NonNull IResponseCallback<Void> callback) {
executor.submit(() -> {
if (!repo.isSyncPossible()) {
repo.updateNetworkStatus();
}
if (repo.isSyncPossible()) {
try {
final var ssoAccount = AccountImporter.getSingleSignOnAccount(getApplication(), localAccount.getAccountName());
try {
final var capabilities = CapabilitiesClient.getCapabilities(getApplication(), ssoAccount, localAccount.getCapabilitiesETag(), ApiProvider.getInstance());
repo.updateCapabilitiesETag(localAccount.getId(), capabilities.getETag());
repo.updateBrand(localAccount.getId(), capabilities.getColor(), capabilities.getTextColor());
localAccount.setColor(capabilities.getColor());
localAccount.setTextColor(capabilities.getTextColor());
BrandingUtil.saveBrandColors(getApplication(), localAccount.getColor(), localAccount.getTextColor());
repo.updateApiVersion(localAccount.getId(), capabilities.getApiVersion());
callback.onSuccess(null);
} catch (Throwable t) {
if (t.getClass() == NextcloudHttpRequestFailedException.class || t instanceof NextcloudHttpRequestFailedException) {
if (((NextcloudHttpRequestFailedException) t).getStatusCode() == HTTP_NOT_MODIFIED) {
Log.d(TAG, "Server returned HTTP Status Code " + ((NextcloudHttpRequestFailedException) t).getStatusCode() + " - Capabilities not modified.");
callback.onSuccess(null);
return;
}
}
callback.onError(t);
}
} catch (NextcloudFilesAppAccountNotFoundException e) {
repo.deleteAccount(localAccount);
callback.onError(e);
}
} else {
if (repo.isNetworkConnected() && repo.isSyncOnlyOnWifi()) {
callback.onError(new IntendedOfflineException("Network is connected, but sync is not possible."));
} else {
callback.onError(new NetworkErrorException("Sync is not possible, because network is not connected."));
}
}
}, "SYNC_CAPABILITIES");
}
use of com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException in project nextcloud-notes by stefan-niedermann.
the class NotesRepository method addAccount.
// Accounts
@AnyThread
public LiveData<ImportStatus> addAccount(@NonNull String url, @NonNull String username, @NonNull String accountName, @NonNull Capabilities capabilities, @Nullable String displayName, @NonNull IResponseCallback<Account> callback) {
final var account = db.getAccountDao().getAccountById(db.getAccountDao().insert(new Account(url, username, accountName, displayName, capabilities)));
if (account == null) {
callback.onError(new Exception("Could not read created account."));
} else {
if (isSyncPossible()) {
syncActive.put(account.getId(), true);
try {
Log.d(TAG, "… starting now");
final NotesImportTask importTask = new NotesImportTask(context, this, account, importExecutor, apiProvider);
return importTask.importNotes(new IResponseCallback<>() {
@Override
public void onSuccess(Void result) {
callback.onSuccess(account);
}
@Override
public void onError(@NonNull Throwable t) {
callback.onError(t);
}
});
} catch (NextcloudFilesAppAccountNotFoundException e) {
Log.e(TAG, "… Could not find " + SingleSignOnAccount.class.getSimpleName() + " for account name " + account.getAccountName());
callback.onError(e);
}
} else {
callback.onError(new NetworkErrorException());
}
}
return new MutableLiveData<>(new ImportStatus());
}
use of com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException in project nextcloud-notes by stefan-niedermann.
the class NoteListWidgetConfigurationActivity method onCreate.
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setResult(RESULT_CANCELED);
repo = NotesRepository.getInstance(this);
final var args = getIntent().getExtras();
if (args != null) {
appWidgetId = args.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
}
if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
Log.d(TAG, "INVALID_APPWIDGET_ID");
finish();
}
viewModel = new ViewModelProvider(this).get(NoteListViewModel.class);
binding = ActivityNoteListConfigurationBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
adapterCategories = new NavigationAdapter(this, new NavigationClickListener() {
@Override
public void onItemClick(NavigationItem item) {
final var data = new NotesListWidgetData();
data.setId(appWidgetId);
if (item.type != null) {
switch(item.type) {
case RECENT:
{
data.setMode(MODE_DISPLAY_ALL);
break;
}
case FAVORITES:
{
data.setMode(MODE_DISPLAY_STARRED);
break;
}
case UNCATEGORIZED:
{
data.setMode(MODE_DISPLAY_CATEGORY);
data.setCategory(null);
}
case DEFAULT_CATEGORY:
default:
{
if (item.getClass() == NavigationItem.CategoryNavigationItem.class) {
data.setMode(MODE_DISPLAY_CATEGORY);
data.setCategory(((NavigationItem.CategoryNavigationItem) item).category);
} else {
data.setMode(MODE_DISPLAY_ALL);
Log.e(TAG, "Unknown item navigation type. Fallback to show " + RECENT);
}
}
}
} else {
data.setMode(MODE_DISPLAY_ALL);
Log.e(TAG, "Unknown item navigation type. Fallback to show " + RECENT);
}
data.setAccountId(localAccount.getId());
data.setThemeMode(NotesApplication.getAppTheme(getApplicationContext()).getModeId());
executor.submit(() -> {
repo.createOrUpdateNoteListWidgetData(data);
final var updateIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, getApplicationContext(), NoteListWidget.class).putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
setResult(RESULT_OK, updateIntent);
getApplicationContext().sendBroadcast(updateIntent);
finish();
});
}
public void onIconClick(NavigationItem item) {
onItemClick(item);
}
});
binding.recyclerView.setAdapter(adapterCategories);
executor.submit(() -> {
try {
this.localAccount = repo.getAccountByName(SingleAccountHelper.getCurrentSingleSignOnAccount(this).name);
} catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) {
e.printStackTrace();
Toast.makeText(this, R.string.widget_not_logged_in, Toast.LENGTH_LONG).show();
// TODO Present user with app login screen
Log.w(TAG, "onCreate: user not logged in");
finish();
}
runOnUiThread(() -> viewModel.getAdapterCategories(localAccount.getId()).observe(this, (navigationItems) -> adapterCategories.setItems(navigationItems)));
});
}
Aggregations