diff --git a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherViewHolder.java index 852c7d40d..1f096c96e 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherViewHolder.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherViewHolder.java @@ -34,6 +34,6 @@ public void bind(@NonNull Account localAccount, @NonNull Consumer onAcc .apply(RequestOptions.circleCropTransform()) .into(binding.accountItemAvatar); itemView.setOnClickListener((v) -> onAccountClick.accept(localAccount)); - binding.delete.setVisibility(View.GONE); + binding.accountContextMenu.setVisibility(View.GONE); } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountAdapter.java index 87cffe2e6..25155c9a9 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountAdapter.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountAdapter.java @@ -24,10 +24,19 @@ public class ManageAccountAdapter extends RecyclerView.Adapter onAccountClick; @NonNull private final Consumer onAccountDelete; + @NonNull + Consumer onChangeNotesPath; + @NonNull + Consumer onChangeFileSuffix; - public ManageAccountAdapter(@NonNull Consumer onAccountClick, @NonNull Consumer onAccountDelete) { + public ManageAccountAdapter(@NonNull Consumer onAccountClick, + @NonNull Consumer onAccountDelete, + @NonNull Consumer onChangeNotesPath, + @NonNull Consumer onChangeFileSuffix) { this.onAccountClick = onAccountClick; this.onAccountDelete = onAccountDelete; + this.onChangeNotesPath = onChangeNotesPath; + this.onChangeFileSuffix = onChangeFileSuffix; setHasStableIds(true); } @@ -48,7 +57,7 @@ public void onBindViewHolder(@NonNull ManageAccountViewHolder holder, int positi holder.bind(localAccount, (localAccountClicked) -> { setCurrentLocalAccount(localAccountClicked); onAccountClick.accept(localAccountClicked); - }, onAccountDelete, currentLocalAccount != null && currentLocalAccount.getId() == localAccount.getId()); + }, onAccountDelete, onChangeNotesPath, onChangeFileSuffix, currentLocalAccount != null && currentLocalAccount.getId() == localAccount.getId()); } @Override diff --git a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountViewHolder.java index fcd8c953e..2c29ce99f 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountViewHolder.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountViewHolder.java @@ -1,26 +1,30 @@ package it.niedermann.owncloud.notes.manageaccounts; -import android.graphics.Color; import android.graphics.drawable.LayerDrawable; import android.net.Uri; +import android.view.Menu; import android.view.View; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; +import androidx.appcompat.widget.PopupMenu; import androidx.core.util.Consumer; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; +import java.util.stream.Stream; + import it.niedermann.nextcloud.sso.glide.SingleSignOnUrl; import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.databinding.ItemAccountChooseBinding; import it.niedermann.owncloud.notes.persistence.entity.Account; +import it.niedermann.owncloud.notes.shared.model.ApiVersion; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static it.niedermann.owncloud.notes.branding.BrandingUtil.applyBrandToLayerDrawable; +import static it.niedermann.owncloud.notes.shared.util.ApiVersionUtil.getPreferredApiVersion; public class ManageAccountViewHolder extends RecyclerView.ViewHolder { @@ -31,7 +35,14 @@ public ManageAccountViewHolder(@NonNull View itemView) { binding = ItemAccountChooseBinding.bind(itemView); } - public void bind(@NonNull Account localAccount, @NonNull Consumer onAccountClick, @Nullable Consumer onAccountDelete, boolean isCurrentAccount) { + public void bind( + @NonNull Account localAccount, + @NonNull Consumer onAccountClick, + @NonNull Consumer onAccountDelete, + @NonNull Consumer onChangeNotesPath, + @NonNull Consumer onChangeFileSuffix, + boolean isCurrentAccount + ) { binding.accountName.setText(localAccount.getUserName()); binding.accountHost.setText(Uri.parse(localAccount.getUrl()).getHost()); Glide.with(itemView.getContext()) @@ -40,12 +51,33 @@ public void bind(@NonNull Account localAccount, @NonNull Consumer onAcc .apply(RequestOptions.circleCropTransform()) .into(binding.accountItemAvatar); itemView.setOnClickListener((v) -> onAccountClick.accept(localAccount)); - if (onAccountDelete == null) { - binding.delete.setVisibility(GONE); - } else { - binding.delete.setVisibility(VISIBLE); - binding.delete.setOnClickListener((v) -> onAccountDelete.accept(localAccount)); - } + binding.accountContextMenu.setVisibility(VISIBLE); + binding.accountContextMenu.setOnClickListener((v) -> { + final PopupMenu popup = new PopupMenu(itemView.getContext(), v); + popup.inflate(R.menu.menu_account); + final ApiVersion preferredApiVersion = getPreferredApiVersion(localAccount.getApiVersion()); + if (preferredApiVersion != null && !preferredApiVersion.supportsSettings()) { + final Menu menu = popup.getMenu(); + Stream.of( + R.id.notes_path, + R.id.file_suffix + ).forEach((i) -> menu.removeItem(menu.findItem(i).getItemId())); + } + popup.setOnMenuItemClickListener(item -> { + if (item.getItemId() == R.id.notes_path) { + onChangeNotesPath.accept(localAccount); + return true; + } else if (item.getItemId() == R.id.file_suffix) { + onChangeFileSuffix.accept(localAccount); + return true; + } else if (item.getItemId() == R.id.delete) { + onAccountDelete.accept(localAccount); + return true; + } + return false; + }); + popup.show(); + }); if (isCurrentAccount) { binding.currentAccountIndicator.setVisibility(VISIBLE); applyBrandToLayerDrawable((LayerDrawable) binding.currentAccountIndicator.getDrawable(), R.id.area, localAccount.getColor()); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsActivity.java index dee5661f4..d1b0e603d 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsActivity.java @@ -1,18 +1,43 @@ package it.niedermann.owncloud.notes.manageaccounts; +import android.accounts.NetworkErrorException; import android.os.Bundle; +import android.util.TypedValue; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ProgressBar; +import android.widget.Spinner; +import android.widget.Toast; +import androidx.annotation.AttrRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.Px; +import androidx.appcompat.app.AlertDialog; import androidx.lifecycle.ViewModelProvider; +import com.nextcloud.android.sso.AccountImporter; +import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException; + import it.niedermann.owncloud.notes.LockedActivity; import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.branding.BrandedAlertDialogBuilder; import it.niedermann.owncloud.notes.branding.BrandedDeleteAlertDialogBuilder; import it.niedermann.owncloud.notes.databinding.ActivityManageAccountsBinding; import it.niedermann.owncloud.notes.exception.ExceptionDialogFragment; +import it.niedermann.owncloud.notes.persistence.NotesRepository; import it.niedermann.owncloud.notes.persistence.entity.Account; import it.niedermann.owncloud.notes.shared.model.IResponseCallback; +import it.niedermann.owncloud.notes.shared.model.NotesSettings; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +import static android.os.Build.VERSION.SDK_INT; +import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; +import static it.niedermann.owncloud.notes.shared.util.ApiVersionUtil.getPreferredApiVersion; public class ManageAccountsActivity extends LockedActivity { @@ -30,7 +55,12 @@ public void onCreate(@Nullable Bundle savedInstanceState) { setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); - adapter = new ManageAccountAdapter(this::selectAccount, this::deleteAccount); + adapter = new ManageAccountAdapter( + this::selectAccount, + this::deleteAccount, + this::onChangeNotesPath, + this::onChangeFileSuffix + ); binding.accounts.setAdapter(adapter); viewModel.getAccounts$().observe(this, (accounts) -> { @@ -83,6 +113,169 @@ public void onError(@NonNull Throwable t) { }); } + private void onChangeNotesPath(@NonNull Account localAccount) { + final NotesRepository repository = NotesRepository.getInstance(getApplicationContext()); + final EditText editText = new EditText(this); + final ViewGroup wrapper = createDialogViewWrapper(); + final AlertDialog 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 Call 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 call, @NonNull Response response) { + final NotesSettings 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 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 call, @NonNull Response response) { + runOnUiThread(() -> { + final NotesSettings body = response.body(); + if (response.isSuccessful() && body != null) { + wrapper.removeAllViews(); + final EditText 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 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()); + } + } + + private void onChangeFileSuffix(@NonNull Account localAccount) { + final NotesRepository repository = NotesRepository.getInstance(getApplicationContext()); + final Spinner spinner = new Spinner(this); + final ViewGroup wrapper = createDialogViewWrapper(); + final ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.settings_file_suffixes, android.R.layout.simple_spinner_item); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner.setAdapter(adapter); + final AlertDialog dialog = new BrandedAlertDialogBuilder(this) + .setTitle(R.string.settings_file_suffix) + .setMessage(R.string.settings_file_suffix_description) + .setView(wrapper) + .setNeutralButton(android.R.string.cancel, null) + .setPositiveButton(R.string.action_edit_save, (v, d) -> new Thread(() -> { + try { + final Call putSettingsCall = repository.putServerSettings(AccountImporter.getSingleSignOnAccount(this, localAccount.getAccountName()), new NotesSettings(null, spinner.getSelectedItem().toString()), getPreferredApiVersion(localAccount.getApiVersion())); + putSettingsCall.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + final NotesSettings body = response.body(); + if (response.isSuccessful() && body != null) { + runOnUiThread(() -> Toast.makeText(ManageAccountsActivity.this, getString(R.string.settings_file_suffix_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 call, @NonNull Throwable t) { + runOnUiThread(() -> ExceptionDialogFragment.newInstance(t).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName())); + } + }); + } catch (NextcloudFilesAppAccountNotFoundException e) { + runOnUiThread(() -> 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 call, @NonNull Response response) { + final NotesSettings body = response.body(); + runOnUiThread(() -> { + if (response.isSuccessful() && body != null) { + for (int i = 0; i < adapter.getCount(); i++) { + if (adapter.getItem(i).equals(body.getFileSuffix())) { + spinner.setSelection(i); + break; + } + } + wrapper.removeAllViews(); + wrapper.addView(spinner); + } else { + dialog.dismiss(); + ExceptionDialogFragment.newInstance(new Exception(getString(R.string.http_status_code, response.code()))).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); + } + }); + } + + @Override + public void onFailure(@NonNull Call 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()); + } + } + + @NonNull + private ViewGroup createDialogViewWrapper() { + final ProgressBar progressBar = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal); + progressBar.setIndeterminate(true); + final FrameLayout wrapper = new FrameLayout(this); + final int paddingVertical = getResources().getDimensionPixelSize(R.dimen.spacer_1x); + final int paddingHorizontal = SDK_INT >= LOLLIPOP_MR1 + ? getDimensionFromAttribute(android.R.attr.dialogPreferredPadding) + : getResources().getDimensionPixelSize(R.dimen.spacer_2x); + wrapper.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); + wrapper.addView(progressBar); + return wrapper; + } + + @Px + private int getDimensionFromAttribute(@SuppressWarnings("SameParameterValue") @AttrRes int attr) { + final TypedValue typedValue = new TypedValue(); + if (getTheme().resolveAttribute(attr, typedValue, true)) + return TypedValue.complexToDimensionPixelSize(typedValue.data, getResources().getDisplayMetrics()); + else { + return 0; + } + } + @Override public void applyBrand(int mainColor, int textColor) { applyBrandToPrimaryToolbar(binding.appBar, binding.toolbar); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java index f2b242d6d..24a286195 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java @@ -59,10 +59,12 @@ import it.niedermann.owncloud.notes.shared.model.IResponseCallback; import it.niedermann.owncloud.notes.shared.model.ISyncCallback; import it.niedermann.owncloud.notes.shared.model.NavigationCategory; +import it.niedermann.owncloud.notes.shared.model.NotesSettings; import it.niedermann.owncloud.notes.shared.model.SyncResultStatus; import it.niedermann.owncloud.notes.shared.util.ApiVersionUtil; import it.niedermann.owncloud.notes.shared.util.NoteUtil; import it.niedermann.owncloud.notes.shared.util.SSOUtil; +import retrofit2.Call; import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION_CODES.O; @@ -908,6 +910,14 @@ public LiveData> getSyncErrors() { return this.syncErrors; } + public Call getServerSettings(@NonNull SingleSignOnAccount ssoAccount, @Nullable ApiVersion preferredApiVersion) { + return ApiProvider.getInstance().getNotesAPI(context, ssoAccount, preferredApiVersion).getSettings(); + } + + public Call putServerSettings(@NonNull SingleSignOnAccount ssoAccount, @NonNull NotesSettings settings, @Nullable ApiVersion preferredApiVersion) { + return ApiProvider.getInstance().getNotesAPI(context, ssoAccount, preferredApiVersion).putSettings(settings); + } + public void updateDisplayName(long id, @Nullable String displayName) { db.getAccountDao().updateDisplayName(id, displayName); } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI.java index 9d955c006..3e552ae69 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI.java @@ -16,6 +16,7 @@ import io.reactivex.Observable; import it.niedermann.owncloud.notes.persistence.entity.Note; import it.niedermann.owncloud.notes.shared.model.ApiVersion; +import it.niedermann.owncloud.notes.shared.model.NotesSettings; import retrofit2.Call; import retrofit2.NextcloudRetrofitApiBuilder; @@ -102,6 +103,23 @@ public Call deleteNote(long noteId) { } } + + public Call getSettings() { + if (ApiVersion.API_VERSION_1_0.equals(usedApiVersion)) { + return notesAPI_1_0.getSettings(); + } else { + throw new UnsupportedOperationException("Used API version " + usedApiVersion + " does not support getSettings()."); + } + } + + public Call putSettings(NotesSettings settings) { + if (ApiVersion.API_VERSION_1_0.equals(usedApiVersion)) { + return notesAPI_1_0.putSettings(settings); + } else { + throw new UnsupportedOperationException("Used API version " + usedApiVersion + " does not support putSettings()."); + } + } + /** * {@link ApiVersion#API_VERSION_0_2} didn't have a separate title property. */ diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_1_0.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_1_0.java index fc4103e37..dfc176c35 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_1_0.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_1_0.java @@ -7,6 +7,7 @@ import io.reactivex.Observable; import it.niedermann.owncloud.notes.persistence.entity.Note; +import it.niedermann.owncloud.notes.shared.model.NotesSettings; import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.DELETE; @@ -33,4 +34,10 @@ public interface NotesAPI_1_0 { @DELETE("notes/{remoteId}") Call deleteNote(@Path("remoteId") long noteId); + + @GET("settings") + Call getSettings(); + + @PUT("settings") + Call putSettings(@Body NotesSettings settings); } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ApiVersion.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ApiVersion.java index 0a42012b3..b35daaca3 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ApiVersion.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ApiVersion.java @@ -10,6 +10,7 @@ @SuppressWarnings("WeakerAccess") public class ApiVersion implements Comparable { private static final Pattern NUMBER_EXTRACTION_PATTERN = Pattern.compile("[0-9]+"); + private static final ApiVersion VERSION_1_2 = new ApiVersion("1.2", 1, 2); public static final ApiVersion API_VERSION_0_2 = new ApiVersion(0, 2); public static final ApiVersion API_VERSION_1_0 = new ApiVersion(1, 0); @@ -79,6 +80,10 @@ public int compareTo(@NonNull ApiVersion compare) { return 0; } + public boolean supportsSettings() { + return getMajor() >= 1 && getMinor() >= 2; + } + /** * Checks only the {@link #major} version. */ diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/NotesSettings.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/NotesSettings.java new file mode 100644 index 000000000..bffb23441 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/NotesSettings.java @@ -0,0 +1,38 @@ +package it.niedermann.owncloud.notes.shared.model; + +import androidx.annotation.Nullable; + +import com.google.gson.annotations.Expose; + +public class NotesSettings { + + @Expose + @Nullable + private String notesPath; + @Expose + @Nullable + private String fileSuffix; + + public NotesSettings(@Nullable String notesPath, @Nullable String fileSuffix) { + this.notesPath = notesPath; + this.fileSuffix = fileSuffix; + } + + @Nullable + public String getNotesPath() { + return notesPath; + } + + public void setNotesPath(@Nullable String notesPath) { + this.notesPath = notesPath; + } + + @Nullable + public String getFileSuffix() { + return fileSuffix; + } + + public void setFileSuffix(@Nullable String fileSuffix) { + this.fileSuffix = fileSuffix; + } +} diff --git a/app/src/main/res/layout/item_account_choose.xml b/app/src/main/res/layout/item_account_choose.xml index 8f321800c..8cfbd4beb 100644 --- a/app/src/main/res/layout/item_account_choose.xml +++ b/app/src/main/res/layout/item_account_choose.xml @@ -64,7 +64,7 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bee381c49..ace142d74 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -293,9 +293,21 @@ Remove %1$s You have to be connected to the internet in order to add an account. + Set folder + Next Previous Backup Repair We detected an irrecoverably state of the app. Please backup your unsynchronized changes and clear the storage of the Notes app. + Folder to store your notes in your Nextcloud + + .txt + .md + + New notes folder: %1$s + File extension + File extension for new notes in your Nextcloud + New file suffix: %1$s + HTTP status code: %1$d