mirror of
https://github.com/nextcloud/notes-android.git
synced 2024-11-21 12:25:57 +03:00
⚙️ Support custom file extensions (Notes ≥ 4.5.0)
Signed-off-by: Stefan Niedermann <info@niedermann.it>
This commit is contained in:
parent
0f4c3a0baf
commit
cfe2a8ccf6
9 changed files with 177 additions and 183 deletions
|
@ -76,7 +76,7 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.0'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6'
|
||||
|
||||
// Nextcloud SSO
|
||||
implementation 'com.github.nextcloud:Android-SingleSignOn:0.6.1'
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package it.niedermann.owncloud.notes.manageaccounts;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import it.niedermann.owncloud.notes.persistence.entity.Account;
|
||||
|
||||
public interface IManageAccountsCallback {
|
||||
|
||||
void onSelect(@NonNull Account account);
|
||||
|
||||
void onDelete(@NonNull Account account);
|
||||
|
||||
void onChangeNotesPath(@NonNull Account account);
|
||||
|
||||
void onChangeFileSuffix(@NonNull Account account);
|
||||
}
|
|
@ -21,22 +21,10 @@ public class ManageAccountAdapter extends RecyclerView.Adapter<ManageAccountView
|
|||
@NonNull
|
||||
private final List<Account> localAccounts = new ArrayList<>();
|
||||
@NonNull
|
||||
private final Consumer<Account> onAccountClick;
|
||||
@NonNull
|
||||
private final Consumer<Account> onAccountDelete;
|
||||
@NonNull
|
||||
Consumer<Account> onChangeNotesPath;
|
||||
@NonNull
|
||||
Consumer<Account> onChangeFileSuffix;
|
||||
private final IManageAccountsCallback callback;
|
||||
|
||||
public ManageAccountAdapter(@NonNull Consumer<Account> onAccountClick,
|
||||
@NonNull Consumer<Account> onAccountDelete,
|
||||
@NonNull Consumer<Account> onChangeNotesPath,
|
||||
@NonNull Consumer<Account> onChangeFileSuffix) {
|
||||
this.onAccountClick = onAccountClick;
|
||||
this.onAccountDelete = onAccountDelete;
|
||||
this.onChangeNotesPath = onChangeNotesPath;
|
||||
this.onChangeFileSuffix = onChangeFileSuffix;
|
||||
public ManageAccountAdapter(@NonNull IManageAccountsCallback callback) {
|
||||
this.callback = callback;
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
|
@ -54,10 +42,7 @@ public class ManageAccountAdapter extends RecyclerView.Adapter<ManageAccountView
|
|||
@Override
|
||||
public void onBindViewHolder(@NonNull ManageAccountViewHolder holder, int position) {
|
||||
final var localAccount = localAccounts.get(position);
|
||||
holder.bind(localAccount, (localAccountClicked) -> {
|
||||
setCurrentLocalAccount(localAccountClicked);
|
||||
onAccountClick.accept(localAccountClicked);
|
||||
}, onAccountDelete, onChangeNotesPath, onChangeFileSuffix, currentLocalAccount != null && currentLocalAccount.getId() == localAccount.getId());
|
||||
holder.bind(localAccount, callback, currentLocalAccount != null && currentLocalAccount.getId() == localAccount.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,31 +1,26 @@
|
|||
package it.niedermann.owncloud.notes.manageaccounts;
|
||||
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.net.Uri;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
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;
|
||||
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
||||
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;
|
||||
|
||||
public class ManageAccountViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final ItemAccountChooseBinding binding;
|
||||
|
@ -37,10 +32,7 @@ public class ManageAccountViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
public void bind(
|
||||
@NonNull Account localAccount,
|
||||
@NonNull Consumer<Account> onAccountClick,
|
||||
@NonNull Consumer<Account> onAccountDelete,
|
||||
@NonNull Consumer<Account> onChangeNotesPath,
|
||||
@NonNull Consumer<Account> onChangeFileSuffix,
|
||||
@NonNull IManageAccountsCallback callback,
|
||||
boolean isCurrentAccount
|
||||
) {
|
||||
binding.accountName.setText(localAccount.getUserName());
|
||||
|
@ -50,28 +42,31 @@ public class ManageAccountViewHolder extends RecyclerView.ViewHolder {
|
|||
.error(R.drawable.ic_account_circle_grey_24dp)
|
||||
.apply(RequestOptions.circleCropTransform())
|
||||
.into(binding.accountItemAvatar);
|
||||
itemView.setOnClickListener((v) -> onAccountClick.accept(localAccount));
|
||||
itemView.setOnClickListener((v) -> callback.onSelect(localAccount));
|
||||
binding.accountContextMenu.setVisibility(VISIBLE);
|
||||
binding.accountContextMenu.setOnClickListener((v) -> {
|
||||
final var popup = new PopupMenu(itemView.getContext(), v);
|
||||
popup.inflate(R.menu.menu_account);
|
||||
|
||||
final var preferredApiVersion = getPreferredApiVersion(localAccount.getApiVersion());
|
||||
if (preferredApiVersion != null && !preferredApiVersion.supportsSettings()) {
|
||||
final var menu = popup.getMenu();
|
||||
Stream.of(
|
||||
R.id.notes_path,
|
||||
R.id.file_suffix
|
||||
).forEach((i) -> menu.removeItem(menu.findItem(i).getItemId()));
|
||||
|
||||
if (preferredApiVersion == null || !preferredApiVersion.supportsFileSuffixChange()) {
|
||||
popup.getMenu().removeItem(popup.getMenu().findItem(R.id.file_suffix).getItemId());
|
||||
}
|
||||
|
||||
if (preferredApiVersion == null || !preferredApiVersion.supportsNotesPathChange()) {
|
||||
popup.getMenu().removeItem(popup.getMenu().findItem(R.id.notes_path).getItemId());
|
||||
}
|
||||
|
||||
popup.setOnMenuItemClickListener(item -> {
|
||||
if (item.getItemId() == R.id.notes_path) {
|
||||
onChangeNotesPath.accept(localAccount);
|
||||
callback.onChangeNotesPath(localAccount);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.file_suffix) {
|
||||
onChangeFileSuffix.accept(localAccount);
|
||||
callback.onChangeFileSuffix(localAccount);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.delete) {
|
||||
onAccountDelete.accept(localAccount);
|
||||
callback.onDelete(localAccount);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
package it.niedermann.owncloud.notes.manageaccounts;
|
||||
|
||||
import static it.niedermann.owncloud.notes.shared.util.ApiVersionUtil.getPreferredApiVersion;
|
||||
|
||||
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.annotation.StringRes;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.nextcloud.android.sso.AccountImporter;
|
||||
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import it.niedermann.owncloud.notes.LockedActivity;
|
||||
import it.niedermann.owncloud.notes.R;
|
||||
import it.niedermann.owncloud.notes.branding.BrandedAlertDialogBuilder;
|
||||
|
@ -35,11 +37,7 @@ 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 {
|
||||
public class ManageAccountsActivity extends LockedActivity implements IManageAccountsCallback {
|
||||
|
||||
private ActivityManageAccountsBinding binding;
|
||||
private ManageAccountsViewModel viewModel;
|
||||
|
@ -55,12 +53,7 @@ public class ManageAccountsActivity extends LockedActivity {
|
|||
setContentView(binding.getRoot());
|
||||
setSupportActionBar(binding.toolbar);
|
||||
|
||||
adapter = new ManageAccountAdapter(
|
||||
this::selectAccount,
|
||||
this::deleteAccount,
|
||||
this::onChangeNotesPath,
|
||||
this::onChangeFileSuffix
|
||||
);
|
||||
adapter = new ManageAccountAdapter(this);
|
||||
binding.accounts.setAdapter(adapter);
|
||||
|
||||
viewModel.getAccounts$().observe(this, (accounts) -> {
|
||||
|
@ -69,7 +62,7 @@ public class ManageAccountsActivity extends LockedActivity {
|
|||
return;
|
||||
}
|
||||
this.adapter.setLocalAccounts(accounts);
|
||||
viewModel.getCurrentAccount(this, new IResponseCallback<Account>() {
|
||||
viewModel.getCurrentAccount(this, new IResponseCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(Account result) {
|
||||
runOnUiThread(() -> adapter.setCurrentLocalAccount(result));
|
||||
|
@ -84,12 +77,13 @@ public class ManageAccountsActivity extends LockedActivity {
|
|||
});
|
||||
}
|
||||
|
||||
private void selectAccount(@NonNull Account accountToSelect) {
|
||||
public void onSelect(@NonNull Account accountToSelect) {
|
||||
adapter.setCurrentLocalAccount(accountToSelect);
|
||||
viewModel.selectAccount(accountToSelect, this);
|
||||
}
|
||||
|
||||
private void deleteAccount(@NonNull Account accountToDelete) {
|
||||
viewModel.countUnsynchronizedNotes(accountToDelete.getId(), new IResponseCallback<Long>() {
|
||||
public void onDelete(@NonNull Account accountToDelete) {
|
||||
viewModel.countUnsynchronizedNotes(accountToDelete.getId(), new IResponseCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(Long unsynchronizedChangesCount) {
|
||||
runOnUiThread(() -> {
|
||||
|
@ -113,38 +107,61 @@ public class ManageAccountsActivity extends LockedActivity {
|
|||
});
|
||||
}
|
||||
|
||||
private void onChangeNotesPath(@NonNull Account localAccount) {
|
||||
public void onChangeNotesPath(@NonNull Account localAccount) {
|
||||
changeAccountSetting(localAccount,
|
||||
R.string.settings_notes_path,
|
||||
R.string.settings_notes_path_description,
|
||||
R.string.settings_notes_path_success,
|
||||
NotesSettings::getNotesPath,
|
||||
property -> new NotesSettings(property, null)
|
||||
);
|
||||
}
|
||||
|
||||
public void onChangeFileSuffix(@NonNull Account localAccount) {
|
||||
changeAccountSetting(localAccount,
|
||||
R.string.settings_file_suffix,
|
||||
R.string.settings_file_suffix_description,
|
||||
R.string.settings_file_suffix_success,
|
||||
NotesSettings::getFileSuffix,
|
||||
property -> new NotesSettings(null, property)
|
||||
);
|
||||
}
|
||||
|
||||
private void changeAccountSetting(@NonNull Account localAccount, @StringRes int title, @StringRes int message, @StringRes int successMessage, @NonNull Function<NotesSettings, String> propertyExtractor, @NonNull Function<String, NotesSettings> settingsFactory) {
|
||||
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)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.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());
|
||||
.setPositiveButton(R.string.action_edit_save, (v, d) -> {
|
||||
final var property = editText.getText().toString();
|
||||
new Thread(() -> {
|
||||
try {
|
||||
final var putSettingsCall = repository.putServerSettings(AccountImporter.getSingleSignOnAccount(this, localAccount.getAccountName()), settingsFactory.apply(property), 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(successMessage, propertyExtractor.apply(body)), 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())
|
||||
@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()))
|
||||
|
@ -155,8 +172,7 @@ public class ManageAccountsActivity extends LockedActivity {
|
|||
final var body = response.body();
|
||||
if (response.isSuccessful() && body != null) {
|
||||
wrapper.removeAllViews();
|
||||
final var editText = new EditText(ManageAccountsActivity.this);
|
||||
editText.setText(body.getNotesPath());
|
||||
editText.setText(propertyExtractor.apply(body));
|
||||
wrapper.addView(editText);
|
||||
} else {
|
||||
dialog.dismiss();
|
||||
|
@ -179,88 +195,13 @@ public class ManageAccountsActivity extends LockedActivity {
|
|||
}
|
||||
}
|
||||
|
||||
private void onChangeFileSuffix(@NonNull Account localAccount) {
|
||||
final var repository = NotesRepository.getInstance(getApplicationContext());
|
||||
final var spinner = new Spinner(this);
|
||||
final var wrapper = createDialogViewWrapper();
|
||||
final var 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 var 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<NotesSettings> 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<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_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<NotesSettings> 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<NotesSettings> call, @NonNull Response<NotesSettings> 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<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());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ViewGroup createDialogViewWrapper() {
|
||||
final var progressBar = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);
|
||||
progressBar.setIndeterminate(true);
|
||||
final var 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);
|
||||
final int paddingHorizontal = getDimensionFromAttribute(android.R.attr.dialogPreferredPadding);
|
||||
wrapper.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical);
|
||||
wrapper.addView(progressBar);
|
||||
return wrapper;
|
||||
|
|
|
@ -4,16 +4,16 @@ package it.niedermann.owncloud.notes.shared.model;
|
|||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class ApiVersion implements Comparable<ApiVersion> {
|
||||
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);
|
||||
public static final ApiVersion API_VERSION_0_2 = new ApiVersion("0.2", 0, 2);
|
||||
public static final ApiVersion API_VERSION_1_0 = new ApiVersion("1.0", 1, 0);
|
||||
public static final ApiVersion API_VERSION_1_2 = new ApiVersion("1.2", 1, 2);
|
||||
public static final ApiVersion API_VERSION_1_3 = new ApiVersion("1.3", 1, 3);
|
||||
|
||||
public static final ApiVersion[] SUPPORTED_API_VERSIONS = new ApiVersion[]{
|
||||
API_VERSION_1_0,
|
||||
|
@ -45,7 +45,7 @@ public class ApiVersion implements Comparable<ApiVersion> {
|
|||
public static ApiVersion of(String versionString) {
|
||||
int major = 0, minor = 0;
|
||||
if (versionString != null) {
|
||||
String[] split = versionString.split("\\.");
|
||||
final String[] split = versionString.split("\\.");
|
||||
if (split.length > 0) {
|
||||
major = extractNumber(split[0]);
|
||||
if (split.length > 1) {
|
||||
|
@ -80,8 +80,19 @@ public class ApiVersion implements Comparable<ApiVersion> {
|
|||
return 0;
|
||||
}
|
||||
|
||||
public boolean supportsSettings() {
|
||||
return getMajor() >= 1 && getMinor() >= 2;
|
||||
/**
|
||||
* While setting the file suffix to <code>.txt</code> or <code>.md</code> was possible starting
|
||||
* with {@link #API_VERSION_1_2}, we will only support this feature with {@link #API_VERSION_1_3}
|
||||
* because it allows us to set any value and skip client side validations.
|
||||
*
|
||||
* @see <a href="https://github.com/nextcloud/notes/blob/master/docs/api/v1.md#settings">Settings API</a>
|
||||
*/
|
||||
public boolean supportsFileSuffixChange() {
|
||||
return getMajor() >= API_VERSION_1_3.getMajor() && getMinor() >= API_VERSION_1_3.getMinor();
|
||||
}
|
||||
|
||||
public boolean supportsNotesPathChange() {
|
||||
return getMajor() >= API_VERSION_1_2.getMajor() && getMinor() >= API_VERSION_1_2.getMinor();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package it.niedermann.owncloud.notes.shared.model;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ApiVersionTest {
|
||||
|
||||
@Test
|
||||
public void shouldOnlyCompareMajorApiVersions() {
|
||||
final var apiVersion = new ApiVersion("1.0", 1, 0);
|
||||
|
||||
assertEquals(1, apiVersion.compareTo(ApiVersion.API_VERSION_0_2));
|
||||
assertEquals(0, apiVersion.compareTo(ApiVersion.API_VERSION_1_0));
|
||||
assertEquals(0, apiVersion.compareTo(ApiVersion.API_VERSION_1_2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldOnlyEqualMajorApiVersions() {
|
||||
final var apiVersion = new ApiVersion("1.0", 1, 0);
|
||||
|
||||
assertNotEquals(apiVersion, ApiVersion.API_VERSION_0_2);
|
||||
assertEquals(apiVersion, ApiVersion.API_VERSION_1_0);
|
||||
assertEquals(apiVersion, ApiVersion.API_VERSION_1_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSupportFileSuffixChangesWithApi1_3andAbove() {
|
||||
assertFalse(ApiVersion.API_VERSION_0_2.supportsFileSuffixChange());
|
||||
assertFalse(ApiVersion.API_VERSION_1_0.supportsFileSuffixChange());
|
||||
assertFalse(ApiVersion.API_VERSION_1_2.supportsFileSuffixChange());
|
||||
assertTrue(ApiVersion.API_VERSION_1_3.supportsFileSuffixChange());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSupportNotesPathChangesWithApi1_2andAbove() {
|
||||
assertFalse(ApiVersion.API_VERSION_0_2.supportsNotesPathChange());
|
||||
assertFalse(ApiVersion.API_VERSION_1_0.supportsNotesPathChange());
|
||||
assertTrue(ApiVersion.API_VERSION_1_2.supportsNotesPathChange());
|
||||
assertTrue(ApiVersion.API_VERSION_1_3.supportsNotesPathChange());
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.3.0-beta05'
|
||||
classpath 'com.android.tools.build:gradle:7.2.2'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
- 📱️ Add option to not keep screen on (#1531)
|
||||
- 🐞 Favorite star in menu not clickable (#1541)
|
||||
- 🐞 Fix back button behavior in widgets (#1412) - by @newhinton
|
||||
- ⚙️ Support custom file extensions (Notes ≥ 4.5.0)
|
||||
- ⚙️ Add monochrome icon (#1544) - by @salixor
|
||||
- ⚙️ Use the new Android 12 SplashScreen API (#1546) - by @salixor
|
||||
- 🌎 Updated translations
|
||||
|
|
Loading…
Reference in a new issue