diff --git a/app/build.gradle b/app/build.gradle index e4b884d734a4d603f3e3a0840c1026b0a2a38260..1ca6cfaf7ac12d85fd4b6f76126364fafccb8aa8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,7 +56,7 @@ dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6' // Nextcloud SSO - implementation 'foundation.e.lib:Android-SingleSignOn:1.0.5-alpha' + implementation 'foundation.e.lib:Android-SingleSignOn:1.0.8-release' implementation ('com.github.stefan-niedermann:android-commons:0.2.7') { exclude group: 'com.github.nextcloud', module: 'Android-SingleSignOn' } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherDialog.java b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherDialog.java index 20c1eed4ff9e3c6da92c586ed4bea7523c4c53b2..fc9335b85e66ea5ccd2a87610a3940405ff72694 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherDialog.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherDialog.java @@ -6,8 +6,8 @@ import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.graphics.drawable.LayerDrawable; -import android.net.Uri; import android.os.Bundle; +import android.view.View; import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; @@ -16,12 +16,16 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import java.util.List; +import java.util.stream.Collectors; + import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.branding.BrandedDialogFragment; import it.niedermann.owncloud.notes.databinding.DialogAccountSwitcherBinding; import it.niedermann.owncloud.notes.manageaccounts.ManageAccountsActivity; import it.niedermann.owncloud.notes.persistence.NotesRepository; import it.niedermann.owncloud.notes.persistence.entity.Account; +import it.niedermann.owncloud.notes.shared.util.AccountSyncUtil; import it.niedermann.owncloud.notes.shared.util.DisplayUtils; /** @@ -66,10 +70,10 @@ public class AccountSwitcherDialog extends BrandedDialogFragment { account$.removeObservers(requireActivity()); binding.accountName.setText(currentLocalAccount.getDisplayName()); - binding.accountHost.setText(Uri.parse(currentLocalAccount.getUrl()).getHost()); + DisplayUtils.setHost(currentLocalAccount, binding.accountHost); Glide.with(requireContext()) .load(DisplayUtils.getAvatarUrl(currentLocalAccount)) - .error(R.drawable.ic_account_circle_grey_24dp) + .error(R.drawable.ic_account_circle_grey_32dp) .apply(RequestOptions.circleCropTransform()) .into(binding.currentAccountItemAvatar); binding.accountLayout.setOnClickListener((v) -> dismiss()); @@ -82,18 +86,14 @@ public class AccountSwitcherDialog extends BrandedDialogFragment { final var localAccounts$ = repo.getAccounts$(); localAccounts$.observe(requireActivity(), (localAccounts) -> { localAccounts$.removeObservers(requireActivity()); - for (final var localAccount : localAccounts) { - if (localAccount.getId() == currentLocalAccount.getId()) { - localAccounts.remove(localAccount); - break; - } - } - adapter.setLocalAccounts(localAccounts); + + setAdapterList(currentLocalAccount, adapter, localAccounts); + setAddLocalAccountButtonVisibility(localAccounts); }); }); binding.addAccount.setOnClickListener((v) -> { - accountSwitcherListener.addAccount(); + accountSwitcherListener.onAddAccountButtonClick(); dismiss(); }); @@ -102,11 +102,29 @@ public class AccountSwitcherDialog extends BrandedDialogFragment { dismiss(); }); + binding.addLocalAccount.setOnClickListener(view -> { + accountSwitcherListener.onAddLocalAccountButtonClick(); + dismiss(); + }); + return new MaterialAlertDialogBuilder(requireContext()) .setView(binding.getRoot()) .create(); } + private void setAddLocalAccountButtonVisibility(List localAccounts) { + final boolean isDeviceLocalAccountPresent = localAccounts.stream() + .anyMatch(account -> AccountSyncUtil.isLocalAccount(requireContext(), account)); + binding.addLocalAccount.setVisibility(isDeviceLocalAccountPresent ? View.GONE : View.VISIBLE); + } + + private void setAdapterList(Account currentLocalAccount, AccountSwitcherAdapter adapter, List localAccounts) { + final List adapterAccounts = localAccounts.stream() + .filter(account -> account.getId() != currentLocalAccount.getId()) + .collect(Collectors.toList()); + adapter.setLocalAccounts(adapterAccounts); + } + public static DialogFragment newInstance(long currentAccountId) { final var dialog = new AccountSwitcherDialog(); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherListener.java b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherListener.java index 87491a163d797658d9f92e35e47b8349bcc9991b..17a83688cfd63f77e7ddd185f62b4ee6d7fc7018 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherListener.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherListener.java @@ -5,7 +5,9 @@ import androidx.annotation.NonNull; import it.niedermann.owncloud.notes.persistence.entity.Account; public interface AccountSwitcherListener { - void addAccount(); + void onAddAccountButtonClick(); void onAccountChosen(@NonNull Account localAccount); + + void onAddLocalAccountButtonClick(); } 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 512c9a9c25d26c7859b821470ab60d788984734a..7070cd3930d89db84fc76243c8b69b7f9650b32e 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 @@ -1,6 +1,5 @@ package it.niedermann.owncloud.notes.accountswitcher; -import android.net.Uri; import android.view.View; import androidx.annotation.NonNull; @@ -26,11 +25,11 @@ public class AccountSwitcherViewHolder extends RecyclerView.ViewHolder { public void bind(@NonNull Account localAccount, @NonNull Consumer onAccountClick) { binding.accountName.setText(localAccount.getDisplayName()); - binding.accountHost.setText(Uri.parse(localAccount.getUrl()).getHost()); + DisplayUtils.setHost(localAccount, binding.accountHost); Glide.with(itemView.getContext()) .load(DisplayUtils.getAvatarUrl(localAccount)) - .placeholder(R.drawable.ic_account_circle_grey_24dp) - .error(R.drawable.ic_account_circle_grey_24dp) + .placeholder(R.drawable.ic_account_circle_grey_32dp) + .error(R.drawable.ic_account_circle_grey_32dp) .apply(RequestOptions.circleCropTransform()) .into(binding.accountItemAvatar); itemView.setOnClickListener((v) -> onAccountClick.accept(localAccount)); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java index 0fced7893d374a51c889bf22698d77c81730b34b..e6ad10e87228b839c2d6d60b1ccc068eea117645 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java @@ -1,7 +1,6 @@ package it.niedermann.owncloud.notes.edit; import static java.lang.Boolean.TRUE; -import static it.niedermann.owncloud.notes.NotesApplication.isDarkThemeActive; import static it.niedermann.owncloud.notes.branding.BrandingUtil.tintMenuIcon; import static it.niedermann.owncloud.notes.edit.EditNoteActivity.ACTION_SHORTCUT; import static it.niedermann.owncloud.notes.shared.util.WidgetUtil.pendingIntentFlagCompat; @@ -11,7 +10,6 @@ import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; -import trikita.log.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -47,9 +45,11 @@ import it.niedermann.owncloud.notes.persistence.entity.Note; import it.niedermann.owncloud.notes.shared.model.ApiVersion; import it.niedermann.owncloud.notes.shared.model.DBStatus; import it.niedermann.owncloud.notes.shared.model.ISyncCallback; +import it.niedermann.owncloud.notes.shared.util.AccountSyncUtil; import it.niedermann.owncloud.notes.shared.util.ApiVersionUtil; import it.niedermann.owncloud.notes.shared.util.NoteUtil; import it.niedermann.owncloud.notes.shared.util.ShareUtil; +import trikita.log.Log; public abstract class BaseNoteFragment extends BrandedFragment implements CategoryDialogListener, EditTitleListener { @@ -121,7 +121,8 @@ public abstract class BaseNoteFragment extends BrandedFragment implements Catego requireActivity().invalidateOptionsMenu(); } } else { - paramNote.setStatus(DBStatus.LOCAL_EDITED); + final var status = AccountSyncUtil.isLocalAccount(requireContext(), localAccount) ? DBStatus.VOID : DBStatus.LOCAL_EDITED; + paramNote.setStatus(status); note = repo.addNote(localAccount.getId(), paramNote); originalNote = null; requireActivity().runOnUiThread(() -> onNoteLoaded(note)); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java index 1d2e02e778fd66f3e756225e46a4d3d6e9214a9f..50676b9d23b0cfad9833e29156305f1ed918ad6a 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java @@ -3,9 +3,6 @@ package it.niedermann.owncloud.notes.importaccount; import android.accounts.NetworkErrorException; import android.content.Intent; import android.os.Bundle; - -import it.niedermann.owncloud.notes.main.MainActivity; -import trikita.log.Log; import android.view.View; import androidx.annotation.NonNull; @@ -33,12 +30,16 @@ import it.niedermann.owncloud.notes.branding.BrandingUtil; import it.niedermann.owncloud.notes.databinding.ActivityImportAccountBinding; import it.niedermann.owncloud.notes.exception.ExceptionDialogFragment; import it.niedermann.owncloud.notes.exception.ExceptionHandler; +import it.niedermann.owncloud.notes.main.MainActivity; import it.niedermann.owncloud.notes.persistence.ApiProvider; import it.niedermann.owncloud.notes.persistence.CapabilitiesClient; import it.niedermann.owncloud.notes.persistence.SyncWorker; import it.niedermann.owncloud.notes.persistence.entity.Account; -import it.niedermann.owncloud.notes.shared.model.Capabilities; +import it.niedermann.owncloud.notes.shared.account.ImportMurenaAccountViewModel; +import it.niedermann.owncloud.notes.shared.account.LocalAccountBundle; +import it.niedermann.owncloud.notes.shared.account.LocalAccountViewModel; import it.niedermann.owncloud.notes.shared.model.IResponseCallback; +import trikita.log.Log; public class ImportAccountActivity extends AppCompatActivity { @@ -50,6 +51,8 @@ public class ImportAccountActivity extends AppCompatActivity { private ImportAccountViewModel importAccountViewModel; private ImportMurenaAccountViewModel importMurenaAccountViewModel; + private LocalAccountViewModel localAccountViewModel; + private ActivityImportAccountBinding binding; @Override @@ -61,13 +64,20 @@ public class ImportAccountActivity extends AppCompatActivity { binding = ActivityImportAccountBinding.inflate(getLayoutInflater()); importAccountViewModel = new ViewModelProvider(this).get(ImportAccountViewModel.class); importMurenaAccountViewModel = new ViewModelProvider(this).get(ImportMurenaAccountViewModel.class); + localAccountViewModel = new ViewModelProvider(this).get(LocalAccountViewModel.class); setContentView(binding.getRoot()); binding.welcomeText.setText(getString(R.string.welcome_text, getString(R.string.app_name))); + handleAddButtonClickListener(); + handleLocalAccount(); + + handleAutoMurenaAccountSetup(); + } + + private void handleAddButtonClickListener() { binding.addButton.setOnClickListener((v) -> { - binding.addButton.setEnabled(false); - binding.addButton.setVisibility(View.INVISIBLE); + setAddButtonVisibility(false); binding.status.setVisibility(View.GONE); try { AccountImporter.pickNewAccount(this); @@ -75,15 +85,24 @@ public class ImportAccountActivity extends AppCompatActivity { UiExceptionManager.showDialogForException(this, e); Log.w(TAG, "============================================================="); Log.w(TAG, "Nextcloud app is not installed. Cannot choose account"); - e.printStackTrace(); + Log.e(TAG, e.getMessage()); } catch (AndroidGetAccountsPermissionNotGranted e) { - binding.addButton.setEnabled(true); - binding.addButton.setVisibility(View.VISIBLE); + setAddButtonVisibility(true); AccountImporter.requestAndroidAccountPermissionsAndPickAccount(this); } }); + } - handleAutoMurenaAccountSetup(); + private void setAddButtonVisibility(boolean enabled) { + int visibility = enabled ? View.VISIBLE : View.INVISIBLE; + + binding.addButton.setEnabled(enabled); + binding.addButton.setVisibility(visibility); + + binding.addLocalButton.setEnabled(enabled); + binding.addLocalButton.setVisibility(visibility); + + binding.textOr.setVisibility(visibility); } @Override @@ -119,11 +138,7 @@ public class ImportAccountActivity extends AppCompatActivity { runOnUiThread(() -> { Log.i(TAG, capabilities.toString()); BrandingUtil.saveBrandColors(ImportAccountActivity.this, capabilities.getColor(), capabilities.getTextColor()); - setResult(RESULT_OK); - Intent intent = new Intent(ImportAccountActivity.this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - finish(); + finishActivity(); }); SyncWorker.update(ImportAccountActivity.this, PreferenceManager.getDefaultSharedPreferences(ImportAccountActivity.this) .getBoolean(getString(R.string.pref_key_background_sync), true)); @@ -140,7 +155,7 @@ public class ImportAccountActivity extends AppCompatActivity { runOnUiThread(() -> status$.observe(ImportAccountActivity.this, (status) -> { binding.progressText.setVisibility(View.VISIBLE); Log.v(TAG, "Status: " + status.count + " of " + status.total); - if(status.count > 0) { + if (status.count > 0) { binding.progressCircular.setIndeterminate(false); } binding.progressText.setText(getString(R.string.progress_import, status.count + 1, status.total)); @@ -176,6 +191,14 @@ public class ImportAccountActivity extends AppCompatActivity { } } + private void finishActivity() { + setResult(RESULT_OK); + Intent intent = new Intent(ImportAccountActivity.this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + finish(); + } + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); @@ -184,8 +207,7 @@ public class ImportAccountActivity extends AppCompatActivity { private void restoreCleanState() { runOnUiThread(() -> { - binding.addButton.setEnabled(true); - binding.addButton.setVisibility(View.VISIBLE); + setAddButtonVisibility(true); binding.progressCircular.setVisibility(View.GONE); binding.progressText.setVisibility(View.GONE); }); @@ -193,8 +215,7 @@ public class ImportAccountActivity extends AppCompatActivity { private void handleAutoMurenaAccountSetup() { if (importMurenaAccountViewModel.isMurenaAccountPresent()) { - binding.addButton.setEnabled(false); - binding.addButton.setVisibility(View.INVISIBLE); + setAddButtonVisibility(false); binding.status.setVisibility(View.GONE); pickMurenaAccount(); @@ -212,9 +233,46 @@ public class ImportAccountActivity extends AppCompatActivity { e.printStackTrace(); } catch (AndroidGetAccountsPermissionNotGranted | NextcloudFilesAppAccountPermissionNotGrantedException e) { - binding.addButton.setEnabled(true); - binding.addButton.setVisibility(View.VISIBLE); + setAddButtonVisibility(true); AccountImporter.requestAndroidAccountPermissionsAndPickAccount(this); } } -} \ No newline at end of file + + + private void handleLocalAccount() { + binding.addLocalButton.setOnClickListener(view -> { + localAccountViewModel.logInToLocalAccount(getAddLocalAccountCallback()); + }); + } + + @NonNull + private IResponseCallback getAddLocalAccountCallback() { + return new IResponseCallback<>() { + @Override + public void onSuccess(@NonNull LocalAccountBundle result) { + onSuccessfullyAddedLocalAccount(result); + } + + @Override + public void onError(@NonNull Throwable throwable) { + errorOnAddingNewAccount(throwable); + } + }; + } + + private void errorOnAddingNewAccount(@NonNull Throwable throwable) { + runOnUiThread(() -> { + restoreCleanState(); + ExceptionDialogFragment.newInstance(throwable).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); + }); + } + + private void onSuccessfullyAddedLocalAccount(@NonNull LocalAccountBundle result) { + runOnUiThread(() -> { + SingleAccountHelper.setCurrentAccount(getApplicationContext(), result.getSingleSignOnAccount().name); + + BrandingUtil.saveBrandColors(ImportAccountActivity.this, result.getCapabilities().getColor(), result.getCapabilities().getTextColor()); + finishActivity(); + }); + } +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java index 6f7e7c392e9704a6d66a8541db227af739fc1e41..c7b40e31ac9111b6134e17294e36bb42e3922be6 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java @@ -15,7 +15,6 @@ import android.accounts.NetworkErrorException; import android.animation.AnimatorInflater; import android.app.SearchManager; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.view.View; @@ -32,6 +31,7 @@ import androidx.core.splashscreen.SplashScreen; import androidx.core.view.GravityCompat; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; +import androidx.preference.PreferenceManager; import androidx.recyclerview.selection.SelectionTracker; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -51,6 +51,7 @@ import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException; import com.nextcloud.android.sso.exceptions.TokenMismatchException; import com.nextcloud.android.sso.exceptions.UnknownErrorException; import com.nextcloud.android.sso.helper.SingleAccountHelper; +import com.nextcloud.android.sso.model.SingleSignOnAccount; import java.net.HttpURLConnection; import java.util.LinkedList; @@ -68,11 +69,9 @@ import it.niedermann.owncloud.notes.databinding.ActivityNotesListViewBinding; import it.niedermann.owncloud.notes.databinding.DrawerLayoutBinding; import it.niedermann.owncloud.notes.edit.EditNoteActivity; import it.niedermann.owncloud.notes.edit.category.CategoryDialogFragment; -import it.niedermann.owncloud.notes.edit.category.CategoryViewModel; import it.niedermann.owncloud.notes.exception.ExceptionDialogFragment; import it.niedermann.owncloud.notes.exception.IntendedOfflineException; import it.niedermann.owncloud.notes.importaccount.ImportAccountActivity; -import it.niedermann.owncloud.notes.importaccount.ImportMurenaAccountViewModel; import it.niedermann.owncloud.notes.main.items.ItemAdapter; import it.niedermann.owncloud.notes.main.items.grid.GridItemDecoration; import it.niedermann.owncloud.notes.main.items.list.NotesListViewItemTouchHelper; @@ -85,8 +84,12 @@ import it.niedermann.owncloud.notes.main.navigation.NavigationItem; import it.niedermann.owncloud.notes.persistence.ApiProvider; import it.niedermann.owncloud.notes.persistence.CapabilitiesClient; import it.niedermann.owncloud.notes.persistence.CapabilitiesWorker; +import it.niedermann.owncloud.notes.persistence.SyncWorker; import it.niedermann.owncloud.notes.persistence.entity.Account; import it.niedermann.owncloud.notes.persistence.entity.Note; +import it.niedermann.owncloud.notes.shared.account.ImportMurenaAccountViewModel; +import it.niedermann.owncloud.notes.shared.account.LocalAccountBundle; +import it.niedermann.owncloud.notes.shared.account.LocalAccountViewModel; import it.niedermann.owncloud.notes.shared.model.CategorySortingMethod; import it.niedermann.owncloud.notes.shared.model.IResponseCallback; import it.niedermann.owncloud.notes.shared.model.NavigationCategory; @@ -106,7 +109,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A protected MainViewModel mainViewModel; private ImportMurenaAccountViewModel importMurenaAccountViewModel; - private CategoryViewModel categoryViewModel; + private LocalAccountViewModel localAccountViewModel; private boolean gridView = true; @@ -142,7 +145,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A mainViewModel = new ViewModelProvider(this).get(MainViewModel.class); importMurenaAccountViewModel = new ViewModelProvider(this).get(ImportMurenaAccountViewModel.class); - categoryViewModel = new ViewModelProvider(this).get(CategoryViewModel.class); + localAccountViewModel = new ViewModelProvider(this).get(LocalAccountViewModel.class); CapabilitiesWorker.update(this); binding = DrawerLayoutBinding.inflate(getLayoutInflater()); activityBinding = ActivityNotesListViewBinding.bind(binding.activityNotesListView.getRoot()); @@ -309,8 +312,8 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A Glide .with(this) .load(DisplayUtils.getAvatarUrl(nextAccount)) - .placeholder(R.drawable.ic_account_circle_grey_24dp) - .error(R.drawable.ic_account_circle_grey_24dp) + .placeholder(R.drawable.ic_account_circle_grey_32dp) + .error(R.drawable.ic_account_circle_grey_32dp) .apply(RequestOptions.circleCropTransform()) .into(activityBinding.launchAccountSwitcher); @@ -483,6 +486,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A @Override public void onSuccess(Void v) { Log.d(TAG, "Successfully synchronized capabilities and notes for " + currentAccount.getAccountName()); + runOnUiThread(() -> swipeRefreshLayout.setRefreshing(false)); } @Override @@ -705,6 +709,9 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A importSnackbar.setAction(R.string.simple_switch, (v) -> mainViewModel.postCurrentAccount(mainViewModel.getLocalAccountByAccountName(ssoAccount.name))); }); Log.i(TAG, capabilities.toString()); + SyncWorker.update(MainActivity.this, PreferenceManager.getDefaultSharedPreferences(MainActivity.this) + .getBoolean(getString(R.string.pref_key_background_sync), true)); + }); } @@ -800,10 +807,35 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A } @Override - public void addAccount() { + public void onAddAccountButtonClick() { askForNewAccount(this); } + @Override + public void onAddLocalAccountButtonClick() { + localAccountViewModel.logInToLocalAccount(new IResponseCallback<>() { + @Override + public void onSuccess(@NonNull LocalAccountBundle result) { + runOnUiThread(() -> { + showAccountImportedSnackBar(result.getSingleSignOnAccount()); + }); + } + + @Override + public void onError(@NonNull Throwable throwable) { + runOnUiThread(() -> ExceptionDialogFragment.newInstance(throwable).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName())); + } + }); + } + + private void showAccountImportedSnackBar(SingleSignOnAccount account) { + final var importSnackBar = BrandedSnackbar.make(coordinatorLayout, R.string.progress_import_indeterminate, Snackbar.LENGTH_INDEFINITE) + .setAnchorView(binding.activityNotesListView.fabCreate); + importSnackBar.setText(R.string.account_imported); + importSnackBar.setAction(R.string.simple_switch, (v) -> mainViewModel.postCurrentAccount(mainViewModel.getLocalAccountByAccountName(account.name))); + importSnackBar.show(); + } + @Override public void onAccountChosen(@NonNull Account localAccount) { binding.drawerLayout.closeDrawer(GravityCompat.START); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/menu/MenuAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/main/menu/MenuAdapter.java index 0f757e8727bc2cb32af4235fe1e08b84a445be18..2dd8b12d396f1487c1039d7c619502fbb7ce9801 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/main/menu/MenuAdapter.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/main/menu/MenuAdapter.java @@ -15,12 +15,16 @@ import com.nextcloud.android.sso.Constants; import com.nextcloud.android.sso.helper.VersionCheckHelper; import com.nextcloud.android.sso.model.FilesAppType; +import java.util.ArrayList; +import java.util.List; + import it.niedermann.owncloud.notes.FormattingHelpActivity; import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.about.AboutActivity; import it.niedermann.owncloud.notes.databinding.ItemNavigationBinding; import it.niedermann.owncloud.notes.persistence.entity.Account; import it.niedermann.owncloud.notes.preferences.PreferencesActivity; +import it.niedermann.owncloud.notes.shared.util.AccountSyncUtil; public class MenuAdapter extends RecyclerView.Adapter { @@ -30,12 +34,18 @@ public class MenuAdapter extends RecyclerView.Adapter { private final Consumer onClick; public MenuAdapter(@NonNull Context context, @NonNull Account account, int settingsRequestCode, @NonNull Consumer onClick) { - this.menuItems = new MenuItem[]{ - new MenuItem(new Intent(context, FormattingHelpActivity.class), R.string.action_formatting_help, R.drawable.ic_baseline_help_outline_24), - new MenuItem(generateTrashbinIntent(context, account), R.string.action_trashbin, R.drawable.ic_delete_grey600_24dp), - new MenuItem(new Intent(context, PreferencesActivity.class), settingsRequestCode, R.string.action_settings, R.drawable.ic_settings_grey600_24dp), - new MenuItem(new Intent(context, AboutActivity.class), R.string.simple_about, R.drawable.ic_info_outline_grey600_24dp) - }; + List menuList = new ArrayList<>(); + menuList.add(new MenuItem(new Intent(context, FormattingHelpActivity.class), R.string.action_formatting_help, R.drawable.ic_baseline_help_outline_24)); + + if (!AccountSyncUtil.isLocalAccount(context, account)) { + menuList.add(new MenuItem(generateTrashbinIntent(context, account), R.string.action_trashbin, R.drawable.ic_delete_grey600_24dp)); + } + + menuList.add(new MenuItem(new Intent(context, PreferencesActivity.class), settingsRequestCode, R.string.action_settings, R.drawable.ic_settings_grey600_24dp)); + menuList.add(new MenuItem(new Intent(context, AboutActivity.class), R.string.simple_about, R.drawable.ic_info_outline_grey600_24dp)); + + this.menuItems = menuList.toArray(new MenuItem[0]); + this.onClick = onClick; setHasStableIds(true); } 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 a8dfd718a410997997d4b9524de132ccacb76350..da624738fffd4930c3455a5ea3092579eb1b50fa 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 @@ -6,7 +6,6 @@ import static it.niedermann.owncloud.notes.branding.BrandingUtil.applyBrandToLay 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; @@ -37,10 +36,10 @@ public class ManageAccountViewHolder extends RecyclerView.ViewHolder { boolean isCurrentAccount ) { binding.accountName.setText(localAccount.getUserName()); - binding.accountHost.setText(Uri.parse(localAccount.getUrl()).getHost()); + DisplayUtils.setHost(localAccount, binding.accountHost); Glide.with(itemView.getContext()) .load(DisplayUtils.getAvatarUrl(localAccount)) - .error(R.drawable.ic_account_circle_grey_24dp) + .error(R.drawable.ic_account_circle_grey_32dp) .apply(RequestOptions.circleCropTransform()) .into(binding.accountItemAvatar); itemView.setOnClickListener((v) -> callback.onSelect(localAccount)); @@ -51,11 +50,13 @@ public class ManageAccountViewHolder extends RecyclerView.ViewHolder { final var preferredApiVersion = getPreferredApiVersion(localAccount.getApiVersion()); - if (preferredApiVersion == null || !preferredApiVersion.supportsFileSuffixChange()) { + boolean isDeviceLocalAccount = AccountSyncUtil.isLocalAccount(itemView.getContext(), localAccount); + + if (preferredApiVersion == null || !preferredApiVersion.supportsFileSuffixChange() || isDeviceLocalAccount) { popup.getMenu().removeItem(popup.getMenu().findItem(R.id.file_suffix).getItemId()); } - if (preferredApiVersion == null || !preferredApiVersion.supportsNotesPathChange()) { + if (preferredApiVersion == null || !preferredApiVersion.supportsNotesPathChange() || isDeviceLocalAccount) { popup.getMenu().removeItem(popup.getMenu().findItem(R.id.notes_path).getItemId()); } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java index 99fee65716de6f3952456e2365e061c6aeef654a..ca8ffeb62f7b0eb3f56e05f06cdc8685686523bf 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java @@ -9,6 +9,7 @@ import androidx.annotation.WorkerThread; import com.nextcloud.android.sso.model.SingleSignOnAccount; import it.niedermann.owncloud.notes.shared.model.Capabilities; +import it.niedermann.owncloud.notes.shared.util.AccountSyncUtil; import it.niedermann.owncloud.notes.shared.util.SSOUtil; import trikita.log.Log; @@ -21,6 +22,10 @@ public class CapabilitiesClient { @WorkerThread public static Capabilities getCapabilities(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount, @Nullable String lastETag, @NonNull ApiProvider apiProvider) throws Throwable { + if (AccountSyncUtil.isLocalAccount(ssoAccount)) { + return new Capabilities(); + } + final var ocsAPI = apiProvider.getOcsAPI(context, ssoAccount); try { final var response = ocsAPI.getCapabilities(lastETag).blockingSingle(); @@ -45,6 +50,10 @@ public class CapabilitiesClient { @WorkerThread @Nullable public static String getDisplayName(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount, @NonNull ApiProvider apiProvider) { + if (AccountSyncUtil.isLocalAccount(ssoAccount)) { + return ssoAccount.name; + } + final var ocsAPI = apiProvider.getOcsAPI(context, ssoAccount); try { final var userResponse = ocsAPI.getUser(SSOUtil.sanitizeUserId(ssoAccount.userId)).execute(); 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 18adb282a8422e9e46fee7d6b312123ebff803ed..e62d06a67e9b8df8f47f10c5dc4332ab33b7c6d8 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 @@ -180,6 +180,11 @@ public class NotesRepository { if (account == null) { callback.onError(new Exception("Could not read created account.")); } else { + if (AccountSyncUtil.isLocalAccount(context, account)) { + callback.onSuccess(account); + return new MutableLiveData<>(new ImportStatus()); + } + if (isSyncPossible()) { syncActive.put(account.getId(), true); try { @@ -422,7 +427,8 @@ public class NotesRepository { @NonNull @MainThread public LiveData addNoteAndSync(Account account, Note note) { - final var entity = new Note(0, null, note.getModified(), note.getTitle(), note.getContent(), note.getCategory(), note.getFavorite(), note.getETag(), DBStatus.LOCAL_EDITED, account.getId(), generateNoteExcerpt(note.getContent(), note.getTitle()), 0); + final var status = getModifiedNoteStatus(account); + final var entity = new Note(0, null, note.getModified(), note.getTitle(), note.getContent(), note.getCategory(), note.getFavorite(), note.getETag(), status, account.getId(), generateNoteExcerpt(note.getContent(), note.getTitle()), 0); final var ret = new MutableLiveData(); executor.submit(() -> ret.postValue(addNote(account.getId(), entity))); return map(ret, newNote -> { @@ -432,6 +438,10 @@ public class NotesRepository { }); } + private DBStatus getModifiedNoteStatus(Account account) { + final var isLocalAccount = AccountSyncUtil.isLocalAccount(context, account); + return isLocalAccount ? DBStatus.VOID : DBStatus.LOCAL_EDITED; + } /** * Inserts a note directly into the Database. * Excerpt will be generated, {@link DBStatus#LOCAL_EDITED} will be applied in case the note has @@ -451,7 +461,8 @@ public class NotesRepository { @MainThread public LiveData moveNoteToAnotherAccount(Account account, @NonNull Note note) { final var fullNote = new Note(null, note.getModified(), note.getTitle(), note.getContent(), note.getCategory(), note.getFavorite(), null); - fullNote.setStatus(DBStatus.LOCAL_EDITED); + final var status = getModifiedNoteStatus(account); + fullNote.setStatus(status); deleteNoteAndSync(account, note.getId()); return addNoteAndSync(account, fullNote); } @@ -481,7 +492,8 @@ public class NotesRepository { @AnyThread public void toggleFavoriteAndSync(Account account, long noteId) { executor.submit(() -> { - db.getNoteDao().toggleFavorite(noteId); + final var status = getModifiedNoteStatus(account); + db.getNoteDao().toggleFavorite(noteId, status); scheduleSync(account, true); }); } @@ -498,7 +510,8 @@ public class NotesRepository { @AnyThread public void setCategory(@NonNull Account account, long noteId, @NonNull String category) { executor.submit(() -> { - db.getNoteDao().updateStatus(noteId, DBStatus.LOCAL_EDITED); + final var status = getModifiedNoteStatus(account); + db.getNoteDao().updateStatus(noteId, status); db.getNoteDao().updateCategory(noteId, category); scheduleSync(account, true); }); @@ -516,12 +529,13 @@ public class NotesRepository { */ @WorkerThread public Note updateNoteAndSync(@NonNull Account localAccount, @NonNull Note oldNote, @Nullable String newContent, @Nullable String newTitle, @Nullable ISyncCallback callback) { + final var status = getModifiedNoteStatus(localAccount); final Note newNote; // Re-read the up to date remoteId from the database because the UI might not have the state after synchronization yet // https://github.com/stefan-niedermann/nextcloud-notes/issues/1198 @Nullable final Long remoteId = db.getNoteDao().getRemoteId(oldNote.getId()); if (newContent == null) { - newNote = new Note(oldNote.getId(), remoteId, oldNote.getModified(), oldNote.getTitle(), oldNote.getContent(), oldNote.getCategory(), oldNote.getFavorite(), oldNote.getETag(), DBStatus.LOCAL_EDITED, localAccount.getId(), oldNote.getExcerpt(), oldNote.getScrollY()); + newNote = new Note(oldNote.getId(), remoteId, oldNote.getModified(), oldNote.getTitle(), oldNote.getContent(), oldNote.getCategory(), oldNote.getFavorite(), oldNote.getETag(), status, localAccount.getId(), oldNote.getExcerpt(), oldNote.getScrollY()); } else { final String title; if (newTitle != null) { @@ -535,7 +549,7 @@ public class NotesRepository { title = oldNote.getTitle(); } } - newNote = new Note(oldNote.getId(), remoteId, Calendar.getInstance(), title, newContent, oldNote.getCategory(), oldNote.getFavorite(), oldNote.getETag(), DBStatus.LOCAL_EDITED, localAccount.getId(), generateNoteExcerpt(newContent, title), oldNote.getScrollY()); + newNote = new Note(oldNote.getId(), remoteId, Calendar.getInstance(), title, newContent, oldNote.getCategory(), oldNote.getFavorite(), oldNote.getETag(), status, localAccount.getId(), generateNoteExcerpt(newContent, title), oldNote.getScrollY()); } int rows = db.getNoteDao().updateNote(newNote); // if data was changed, set new status and schedule sync (with callback); otherwise invoke callback directly. @@ -830,8 +844,8 @@ public class NotesRepository { * @param onlyLocalChanges Whether to only push local changes to the server or to also load the whole list of notes from the server. */ public synchronized void scheduleSync(@Nullable Account account, boolean onlyLocalChanges) { - if (account == null) { - Log.i(TAG, SingleSignOnAccount.class.getSimpleName() + " is null. Is this a local account?"); + if (account == null || AccountSyncUtil.isLocalAccount(context, account)) { + Log.i(TAG, SingleSignOnAccount.class.getSimpleName() + " is null or local account."); syncStatus.postValue(false); } else { syncActive.putIfAbsent(account.getId(), false); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/SyncWorker.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/SyncWorker.java index e10b80bfda14b0598b67802277cb22aa5c7bf144..76bb89f8fdd432efcfab229dd834e9d334b90e9b 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/SyncWorker.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/SyncWorker.java @@ -1,6 +1,8 @@ package it.niedermann.owncloud.notes.persistence; import android.content.Context; + +import it.niedermann.owncloud.notes.shared.util.AccountSyncUtil; import trikita.log.Log; import androidx.annotation.NonNull; @@ -15,6 +17,7 @@ import androidx.work.WorkerParameters; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public class SyncWorker extends Worker { @@ -33,7 +36,10 @@ public class SyncWorker extends Worker { @Override public Result doWork() { final var repo = NotesRepository.getInstance(getApplicationContext()); - final var accounts = repo.getAccounts(); + final var accounts = repo.getAccounts() + .stream().filter(account -> !AccountSyncUtil.isLocalAccount(getApplicationContext(), account)) + .collect(Collectors.toList()); + final var latch = new CountDownLatch(accounts.size()); for (final var account : accounts) { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/NoteDao.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/NoteDao.java index 245d34e9de1f97f15bc115a809330b4aee1e2dcb..db143f86f3fd77f9d375b2b92eb81b40766359b5 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/NoteDao.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/NoteDao.java @@ -161,8 +161,8 @@ public interface NoteDao { @Query("SELECT * FROM NOTE WHERE status != 'LOCAL_DELETED' AND accountId = :accountId ORDER BY modified DESC LIMIT 4") List getRecentNotes(long accountId); - @Query("UPDATE NOTE SET status = 'LOCAL_EDITED', favorite = ((favorite | 1) - (favorite & 1)) WHERE id = :id") - void toggleFavorite(long id); + @Query("UPDATE NOTE SET status = :status, favorite = ((favorite | 1) - (favorite & 1)) WHERE id = :id") + void toggleFavorite(long id, DBStatus status); @Query("UPDATE NOTE SET remoteId = :remoteId WHERE id = :id") void updateRemoteId(long id, Long remoteId); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/account/AccountChooserViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/account/AccountChooserViewHolder.java index 494f9291753a2e02c1dc8761ce75ec5cf296088e..89e16d4c2b54b3b09c954775b610fd77966606b0 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/shared/account/AccountChooserViewHolder.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/account/AccountChooserViewHolder.java @@ -25,8 +25,8 @@ public class AccountChooserViewHolder extends RecyclerView.ViewHolder { Glide .with(binding.accountItemAvatar.getContext()) .load(DisplayUtils.getAvatarUrl(localAccount)) - .placeholder(R.drawable.ic_account_circle_grey_24dp) - .error(R.drawable.ic_account_circle_grey_24dp) + .placeholder(R.drawable.ic_account_circle_grey_32dp) + .error(R.drawable.ic_account_circle_grey_32dp) .apply(RequestOptions.circleCropTransform()) .into(binding.accountItemAvatar); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportMurenaAccountViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/account/ImportMurenaAccountViewModel.java similarity index 97% rename from app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportMurenaAccountViewModel.java rename to app/src/main/java/it/niedermann/owncloud/notes/shared/account/ImportMurenaAccountViewModel.java index 002e794b64b3e27dab0d4cbc50f52608fb2a9b9b..dc0bef13d86668116b9d5bf277ad296052c75991 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportMurenaAccountViewModel.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/account/ImportMurenaAccountViewModel.java @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -package it.niedermann.owncloud.notes.importaccount; +package it.niedermann.owncloud.notes.shared.account; import android.accounts.Account; import android.app.Application; diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/account/LocalAccountBundle.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/account/LocalAccountBundle.java new file mode 100644 index 0000000000000000000000000000000000000000..55ae072f44e4bb5d1096cc4e4eb8d3dffb2e4fe1 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/account/LocalAccountBundle.java @@ -0,0 +1,46 @@ +/* + * Copyright MURENA SAS 2024 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package it.niedermann.owncloud.notes.shared.account; + +import com.nextcloud.android.sso.model.SingleSignOnAccount; + +import it.niedermann.owncloud.notes.persistence.entity.Account; +import it.niedermann.owncloud.notes.shared.model.Capabilities; + +public class LocalAccountBundle { + private final SingleSignOnAccount singleSignOnAccount; + private final Account account; + private final Capabilities capabilities; + + public LocalAccountBundle(SingleSignOnAccount singleSignOnAccount, Account account, Capabilities capabilities) { + this.singleSignOnAccount = singleSignOnAccount; + this.account = account; + this.capabilities = capabilities; + } + + public SingleSignOnAccount getSingleSignOnAccount() { + return singleSignOnAccount; + } + + public Account getAccount() { + return account; + } + + public Capabilities getCapabilities() { + return capabilities; + } +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/account/LocalAccountViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/account/LocalAccountViewModel.java new file mode 100644 index 0000000000000000000000000000000000000000..f6bf22ecec367331b37550fdba4c58a0e6d326a5 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/account/LocalAccountViewModel.java @@ -0,0 +1,80 @@ +/* + * Copyright MURENA SAS 2024 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package it.niedermann.owncloud.notes.shared.account; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; + +import com.nextcloud.android.sso.AccountImporter; +import com.nextcloud.android.sso.model.SingleSignOnAccount; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import it.niedermann.owncloud.notes.persistence.ApiProvider; +import it.niedermann.owncloud.notes.persistence.NotesRepository; +import it.niedermann.owncloud.notes.persistence.entity.Account; +import it.niedermann.owncloud.notes.shared.model.Capabilities; +import it.niedermann.owncloud.notes.shared.model.IResponseCallback; +import trikita.log.Log; + +public class LocalAccountViewModel extends AndroidViewModel { + + private static final String TAG = LocalAccountViewModel.class.getSimpleName(); + + @NonNull + private final NotesRepository notesRepository; + + @NonNull + private final ExecutorService executor; + + public LocalAccountViewModel(@NonNull Application application) { + super(application); + notesRepository = NotesRepository.getInstance(application); + executor = Executors.newSingleThreadExecutor(); + } + + public void logInToLocalAccount(@NonNull IResponseCallback callback) { + executor.submit(() -> { + SingleSignOnAccount singleSignOnAccount = AccountImporter.pickLocalAccount(getApplication()); + Log.i(TAG, "Added local account: " + "name:" + singleSignOnAccount.name); + try { + final var capabilities = new Capabilities(); + final String displayName = singleSignOnAccount.name; + notesRepository.addAccount(singleSignOnAccount.url, singleSignOnAccount.userId, singleSignOnAccount.name, capabilities, displayName, new IResponseCallback<>() { + @Override + public void onSuccess(Account account) { + final var bundle = new LocalAccountBundle(singleSignOnAccount, account, capabilities); + callback.onSuccess(bundle); + } + + @Override + public void onError(@NonNull Throwable throwable) { + Log.e(TAG, throwable); + callback.onError(throwable); + } + }); + } catch (Throwable t) { + ApiProvider.getInstance().invalidateAPICache(singleSignOnAccount); + Log.e(TAG, t); + callback.onError(t); + } + }); + } +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/util/AccountSyncUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/util/AccountSyncUtil.java index e02d6a5e4ff75048602c18068af1c05fdf7a590f..34b58463ce6be17cb06ab3b46bb59041855fb2ce 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/shared/util/AccountSyncUtil.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/util/AccountSyncUtil.java @@ -22,6 +22,10 @@ import android.content.Context; import androidx.annotation.NonNull; +import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException; +import com.nextcloud.android.sso.helper.SingleAccountHelper; +import com.nextcloud.android.sso.model.SingleSignOnAccount; + import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -72,4 +76,18 @@ public final class AccountSyncUtil { .stream() .anyMatch(account -> accountName.equals(account.name)); } + + public static boolean isLocalAccount(@NonNull Context context, @NonNull Account account) { + try { + return SingleAccountHelper.isLocalAccount(context, account.getAccountName()); + } catch (NextcloudFilesAppAccountNotFoundException e) { + Log.e(TAG, "Failed to check is local account or not", e); + } + + return false; + } + + public static boolean isLocalAccount(@NonNull SingleSignOnAccount account) { + return SingleAccountHelper.isLocalAccount(account); + } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/util/DisplayUtils.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/util/DisplayUtils.java index 0d1388d9c1df124169ed975346653bd0179244ad..d42cd4cbbe775452edbe18e6cc09a2d540fc9fa3 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/shared/util/DisplayUtils.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/util/DisplayUtils.java @@ -13,6 +13,7 @@ import android.os.Build; import android.util.TypedValue; import android.view.View; import android.view.WindowInsets; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.view.ViewCompat; @@ -109,4 +110,14 @@ public class DisplayUtils { public static String getAvatarUrl(@NonNull Account account) { return account.getUrl() + "/index.php/avatar/" + Uri.encode(SSOUtil.sanitizeUserId(account.getUserName())) + "/64"; } + + public static void setHost(@NonNull Account account, @NonNull TextView textView) { + if (account.getUrl().trim().isEmpty()) { + textView.setVisibility(View.GONE); + return; + } + + textView.setVisibility(View.VISIBLE); + textView.setText(Uri.parse(account.getUrl()).getHost()); + } } diff --git a/app/src/main/res/drawable/bg_rounded_corner.xml b/app/src/main/res/drawable/bg_rounded_corner.xml new file mode 100644 index 0000000000000000000000000000000000000000..aa4cf2f5fe629a60e9095f26a8efc5606a99ba97 --- /dev/null +++ b/app/src/main/res/drawable/bg_rounded_corner.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_account_circle_grey_24dp.xml b/app/src/main/res/drawable/ic_account_circle_grey_24dp.xml deleted file mode 100644 index 968c9764cacedeff32b57b9b263874953c28be15..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/ic_account_circle_grey_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_account_circle_grey_32dp.xml b/app/src/main/res/drawable/ic_account_circle_grey_32dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..eebd52226b06d99a8b3a14fd111998550f4f6990 --- /dev/null +++ b/app/src/main/res/drawable/ic_account_circle_grey_32dp.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_phone_android_24dp.xml b/app/src/main/res/drawable/ic_phone_android_24dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..b9bb300f68b0c22059f9b134ed296560ce35ae52 --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_android_24dp.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/app/src/main/res/layout/activity_import_account.xml b/app/src/main/res/layout/activity_import_account.xml index 123c63d3af745b0b810872747686ae03d7bdb955..8780eca33273733df674917cf46aca059ff4563c 100644 --- a/app/src/main/res/layout/activity_import_account.xml +++ b/app/src/main/res/layout/activity_import_account.xml @@ -16,43 +16,88 @@ + android:scaleType="centerCrop" + app:srcCompat="@drawable/ic_launcher_foreground_full" + tools:targetApi="s" /> + + + android:layout_marginHorizontal="24dp" + android:textColor="@color/e_secondary_text_color" + android:textSize="14sp" + android:text="@string/welcome_details" />