Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-notes.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2021-09-30 13:36:14 +0300
committerStefan Niedermann <info@niedermann.it>2021-09-30 13:36:14 +0300
commit5801f00bfb79b19b02dc8fcb6862ed8a7bb71a1d (patch)
tree83a657452dbc8d1ee7c096a96c67d2de6d915e97 /app/src/main
parent411c61c21dd6a0f9df93da62e38d837d2de7b66d (diff)
#761 Import notes one by one to avoid read timeout for the first sync
Signed-off-by: Stefan Niedermann <info@niedermann.it>
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java13
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountViewModel.java7
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java22
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java5
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesImportTask.java84
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java38
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI.java21
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_0_2.java6
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_1_0.java6
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/shared/model/ImportStatus.java10
-rw-r--r--app/src/main/res/layout/activity_import_account.xml16
-rw-r--r--app/src/main/res/values/strings.xml4
12 files changed, 213 insertions, 19 deletions
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 1e50ac0f..54e92baf 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
@@ -96,7 +96,7 @@ public class ImportAccountActivity extends AppCompatActivity {
Log.i(TAG, "Loading capabilities for " + ssoAccount.name);
final var capabilities = CapabilitiesClient.getCapabilities(getApplicationContext(), ssoAccount, null, ApiProvider.getInstance());
final String displayName = CapabilitiesClient.getDisplayName(getApplicationContext(), ssoAccount, ApiProvider.getInstance());
- importAccountViewModel.addAccount(ssoAccount.url, ssoAccount.userId, ssoAccount.name, capabilities, displayName, new IResponseCallback<Account>() {
+ final var status$ = importAccountViewModel.addAccount(ssoAccount.url, ssoAccount.userId, ssoAccount.name, capabilities, displayName, new IResponseCallback<>() {
/**
* Update syncing when adding account
@@ -123,6 +123,16 @@ 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) {
+ binding.progressCircular.setIndeterminate(false);
+ }
+ binding.progressText.setText(getString(R.string.progress_import, status.count + 1, status.total));
+ binding.progressCircular.setProgress(status.count);
+ binding.progressCircular.setMax(status.total);
+ }));
} catch (Throwable t) {
t.printStackTrace();
ApiProvider.getInstance().invalidateAPICache(ssoAccount);
@@ -162,6 +172,7 @@ public class ImportAccountActivity extends AppCompatActivity {
runOnUiThread(() -> {
binding.addButton.setEnabled(true);
binding.progressCircular.setVisibility(View.GONE);
+ binding.progressText.setVisibility(View.GONE);
});
}
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountViewModel.java
index 70b3b565..1d60a043 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountViewModel.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountViewModel.java
@@ -11,11 +11,10 @@ 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 it.niedermann.owncloud.notes.shared.model.ImportStatus;
public class ImportAccountViewModel extends AndroidViewModel {
- private static final String TAG = ImportAccountViewModel.class.getSimpleName();
-
@NonNull
private final NotesRepository repo;
@@ -24,7 +23,7 @@ public class ImportAccountViewModel extends AndroidViewModel {
this.repo = NotesRepository.getInstance(application);
}
- public void addAccount(@NonNull String url, @NonNull String username, @NonNull String accountName, @NonNull Capabilities capabilities, @Nullable String displayName, @NonNull IResponseCallback<Account> callback) {
- repo.addAccount(url, username, accountName, capabilities, displayName, callback);
+ public LiveData<ImportStatus> addAccount(@NonNull String url, @NonNull String username, @NonNull String accountName, @NonNull Capabilities capabilities, @Nullable String displayName, @NonNull IResponseCallback<Account> callback) {
+ return repo.addAccount(url, username, accountName, capabilities, displayName, callback);
}
}
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 ee079fbd..132acc9c 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
@@ -668,27 +668,41 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
AccountImporter.onActivityResult(requestCode, resultCode, data, this, (ssoAccount) -> {
CapabilitiesWorker.update(this);
executor.submit(() -> {
+ final var importSnackbar = BrandedSnackbar.make(binding.drawerLayout, R.string.progress_import_indeterminate, Snackbar.LENGTH_INDEFINITE);
Log.i(TAG, "Added account: " + "name:" + ssoAccount.name + ", " + ssoAccount.url + ", userId" + ssoAccount.userId);
try {
Log.i(TAG, "Refreshing capabilities for " + ssoAccount.name);
final var capabilities = CapabilitiesClient.getCapabilities(getApplicationContext(), ssoAccount, null, ApiProvider.getInstance());
final String displayName = CapabilitiesClient.getDisplayName(getApplicationContext(), ssoAccount, ApiProvider.getInstance());
- mainViewModel.addAccount(ssoAccount.url, ssoAccount.userId, ssoAccount.name, capabilities, displayName, new IResponseCallback<Account>() {
+ final var status$ = mainViewModel.addAccount(ssoAccount.url, ssoAccount.userId, ssoAccount.name, capabilities, displayName, new IResponseCallback<Account>() {
@Override
public void onSuccess(Account result) {
executor.submit(() -> {
+ runOnUiThread(() -> {
+ importSnackbar.setText(R.string.account_imported);
+ importSnackbar.setAction(R.string.simple_switch, (v) -> mainViewModel.postCurrentAccount(mainViewModel.getLocalAccountByAccountName(ssoAccount.name)));
+ });
Log.i(TAG, capabilities.toString());
- final var a = mainViewModel.getLocalAccountByAccountName(ssoAccount.name);
- runOnUiThread(() -> mainViewModel.postCurrentAccount(a));
});
}
@Override
public void onError(@NonNull Throwable t) {
- runOnUiThread(() -> ExceptionDialogFragment.newInstance(t).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()));
+ runOnUiThread(() -> {
+ importSnackbar.dismiss();
+ ExceptionDialogFragment.newInstance(t).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
+ });
}
});
+ runOnUiThread(() -> status$.observe(this, (status) -> {
+ importSnackbar.show();
+ Log.v(TAG, "Status: " + status.count + " of " + status.total);
+ if(status.count > 0) {
+ importSnackbar.setText(getString(R.string.progress_import, status.count + 1, status.total));
+ }
+ }));
} catch (Throwable e) {
+ importSnackbar.dismiss();
ApiProvider.getInstance().invalidateAPICache(ssoAccount);
// Happens when importing an already existing account the second time
if (e instanceof TokenMismatchException && mainViewModel.getLocalAccountByAccountName(ssoAccount.name) != null) {
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java
index e7cf1669..b52fdc79 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java
@@ -46,6 +46,7 @@ import it.niedermann.owncloud.notes.persistence.entity.SingleNoteWidgetData;
import it.niedermann.owncloud.notes.shared.model.Capabilities;
import it.niedermann.owncloud.notes.shared.model.CategorySortingMethod;
import it.niedermann.owncloud.notes.shared.model.IResponseCallback;
+import it.niedermann.owncloud.notes.shared.model.ImportStatus;
import it.niedermann.owncloud.notes.shared.model.Item;
import it.niedermann.owncloud.notes.shared.model.NavigationCategory;
@@ -538,8 +539,8 @@ public class MainViewModel extends AndroidViewModel {
});
}
- public void addAccount(@NonNull String url, @NonNull String username, @NonNull String accountName, @NonNull Capabilities capabilities, @Nullable String displayName, @NonNull IResponseCallback<Account> callback) {
- repo.addAccount(url, username, accountName, capabilities, displayName, callback);
+ public LiveData<ImportStatus> addAccount(@NonNull String url, @NonNull String username, @NonNull String accountName, @NonNull Capabilities capabilities, @Nullable String displayName, @NonNull IResponseCallback<Account> callback) {
+ return repo.addAccount(url, username, accountName, capabilities, displayName, callback);
}
public LiveData<Note> getFullNote$(long id) {
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesImportTask.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesImportTask.java
new file mode 100644
index 00000000..acdf1441
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesImportTask.java
@@ -0,0 +1,84 @@
+package it.niedermann.owncloud.notes.persistence;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
+import com.nextcloud.android.sso.AccountImporter;
+import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import it.niedermann.owncloud.notes.persistence.entity.Account;
+import it.niedermann.owncloud.notes.persistence.sync.NotesAPI;
+import it.niedermann.owncloud.notes.shared.model.IResponseCallback;
+import it.niedermann.owncloud.notes.shared.model.ImportStatus;
+import it.niedermann.owncloud.notes.shared.util.ApiVersionUtil;
+
+
+public class NotesImportTask {
+
+ private static final String TAG = NotesImportTask.class.getSimpleName();
+
+ private final NotesAPI notesAPI;
+ @NonNull
+ private final NotesRepository repo;
+ @NonNull
+ private final Account localAccount;
+ @NonNull
+ private final ExecutorService executor;
+ @NonNull
+ private final ExecutorService fetchExecutor;
+
+ NotesImportTask(@NonNull Context context, @NonNull NotesRepository repo, @NonNull Account localAccount, @NonNull ExecutorService executor, @NonNull ApiProvider apiProvider) throws NextcloudFilesAppAccountNotFoundException {
+ this(context, repo, localAccount, executor, Executors.newFixedThreadPool(20), apiProvider);
+ }
+
+ private NotesImportTask(@NonNull Context context, @NonNull NotesRepository repo, @NonNull Account localAccount, @NonNull ExecutorService executor, @NonNull ExecutorService fetchExecutor, @NonNull ApiProvider apiProvider) throws NextcloudFilesAppAccountNotFoundException {
+ this.repo = repo;
+ this.localAccount = localAccount;
+ this.executor = executor;
+ this.fetchExecutor = fetchExecutor;
+ this.notesAPI = apiProvider.getNotesAPI(context, AccountImporter.getSingleSignOnAccount(context, localAccount.getAccountName()), ApiVersionUtil.getPreferredApiVersion(localAccount.getApiVersion()));
+ }
+
+ public LiveData<ImportStatus> importNotes(@NonNull IResponseCallback<Void> callback) {
+ final var status$ = new MutableLiveData<ImportStatus>();
+ Log.i(TAG, "STARTING IMPORT");
+ executor.submit(() -> {
+ Log.i(TAG, "… Fetching notes IDs");
+ final var status = new ImportStatus();
+ final var remoteIds = notesAPI.getNotesIDs().blockingSingle();
+ status.total = remoteIds.size();
+ status$.postValue(status);
+ Log.i(TAG, "… Total count: " + remoteIds.size());
+ final var latch = new CountDownLatch(remoteIds.size());
+ for (long id : remoteIds) {
+ fetchExecutor.submit(() -> {
+ try {
+ repo.addNote(localAccount.getId(), notesAPI.getNote(id).blockingSingle().getResponse());
+ } catch (Throwable t) {
+ Log.w(TAG, "Could not import note with remoteId " + id + ": " + t.getMessage());
+ status.warnings.add(t);
+ }
+ status.count++;
+ status$.postValue(status);
+ latch.countDown();
+ });
+ }
+ try {
+ latch.await();
+ Log.i(TAG, "IMPORT FINISHED");
+ callback.onSuccess(null);
+ } catch (InterruptedException e) {
+ callback.onError(e);
+ }
+ });
+ return status$;
+ }
+}
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 59eafa05..8963d87f 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
@@ -58,6 +58,7 @@ import it.niedermann.owncloud.notes.shared.model.DBStatus;
import it.niedermann.owncloud.notes.shared.model.ENavigationCategoryType;
import it.niedermann.owncloud.notes.shared.model.IResponseCallback;
import it.niedermann.owncloud.notes.shared.model.ISyncCallback;
+import it.niedermann.owncloud.notes.shared.model.ImportStatus;
import it.niedermann.owncloud.notes.shared.model.NavigationCategory;
import it.niedermann.owncloud.notes.shared.model.NotesSettings;
import it.niedermann.owncloud.notes.shared.model.SyncResultStatus;
@@ -86,6 +87,7 @@ public class NotesRepository {
private final ApiProvider apiProvider;
private final ExecutorService executor;
private final ExecutorService syncExecutor;
+ private final ExecutorService importExecutor;
private final Context context;
private final NotesDatabase db;
private final String defaultNonEmptyTitle;
@@ -138,16 +140,17 @@ public class NotesRepository {
public static synchronized NotesRepository getInstance(@NonNull Context context) {
if (instance == null) {
- instance = new NotesRepository(context, NotesDatabase.getInstance(context.getApplicationContext()), Executors.newCachedThreadPool(), Executors.newSingleThreadExecutor(), ApiProvider.getInstance());
+ instance = new NotesRepository(context, NotesDatabase.getInstance(context.getApplicationContext()), Executors.newCachedThreadPool(), Executors.newSingleThreadExecutor(), Executors.newSingleThreadExecutor(), ApiProvider.getInstance());
}
return instance;
}
- private NotesRepository(@NonNull final Context context, @NonNull final NotesDatabase db, @NonNull final ExecutorService executor, @NonNull final ExecutorService syncExecutor, @NonNull ApiProvider apiProvider) {
+ private NotesRepository(@NonNull final Context context, @NonNull final NotesDatabase db, @NonNull final ExecutorService executor, @NonNull final ExecutorService syncExecutor, @NonNull final ExecutorService importExecutor, @NonNull ApiProvider apiProvider) {
this.context = context.getApplicationContext();
this.db = db;
this.executor = executor;
this.syncExecutor = syncExecutor;
+ this.importExecutor = importExecutor;
this.apiProvider = apiProvider;
this.defaultNonEmptyTitle = NoteUtil.generateNonEmptyNoteTitle("", this.context);
this.syncOnlyOnWifiKey = context.getApplicationContext().getResources().getString(R.string.pref_key_wifi_only);
@@ -166,13 +169,36 @@ public class NotesRepository {
// Accounts
@AnyThread
- public void addAccount(@NonNull String url, @NonNull String username, @NonNull String accountName, @NonNull Capabilities capabilities, @Nullable String displayName, @NonNull IResponseCallback<Account> callback) {
- final var createdAccount = db.getAccountDao().getAccountById(db.getAccountDao().insert(new Account(url, username, accountName, displayName, capabilities)));
- if (createdAccount == null) {
+ public LiveData<ImportStatus> addAccount(@NonNull String url, @NonNull String username, @NonNull String accountName, @NonNull Capabilities capabilities, @Nullable String displayName, @NonNull IResponseCallback<Account> callback) {
+ final var account = db.getAccountDao().getAccountById(db.getAccountDao().insert(new Account(url, username, accountName, displayName, capabilities)));
+ if (account == null) {
callback.onError(new Exception("Could not read created account."));
} else {
- callback.onSuccess(createdAccount);
+ if (isSyncPossible()) {
+ syncActive.put(account.getId(), true);
+ try {
+ Log.d(TAG, "... starting now");
+ final NotesImportTask importTask = new NotesImportTask(context, this, account, importExecutor, apiProvider);
+ return importTask.importNotes(new IResponseCallback<>() {
+ @Override
+ public void onSuccess(Void result) {
+ callback.onSuccess(account);
+ }
+
+ @Override
+ public void onError(@NonNull Throwable t) {
+ callback.onError(t);
+ }
+ });
+ } catch (NextcloudFilesAppAccountNotFoundException e) {
+ Log.e(TAG, "... Could not find " + SingleSignOnAccount.class.getSimpleName() + " for account name " + account.getAccountName());
+ callback.onError(e);
+ }
+ } else {
+ callback.onError(new NetworkErrorException());
+ }
}
+ return new MutableLiveData<>(new ImportStatus());
}
@WorkerThread
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 3e552ae6..4f8bee92 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
@@ -12,6 +12,7 @@ import com.nextcloud.android.sso.api.ParsedResponse;
import java.util.Calendar;
import java.util.List;
+import java.util.stream.Collectors;
import io.reactivex.Observable;
import it.niedermann.owncloud.notes.persistence.entity.Note;
@@ -69,6 +70,26 @@ public class NotesAPI {
}
}
+ public Observable<List<Long>> getNotesIDs() {
+ if (ApiVersion.API_VERSION_1_0.equals(usedApiVersion)) {
+ return notesAPI_1_0.getNotesIDs().map(response -> response.getResponse().stream().map(Note::getRemoteId).collect(Collectors.toList()));
+ } else if (ApiVersion.API_VERSION_0_2.equals(usedApiVersion)) {
+ return notesAPI_0_2.getNotesIDs().map(response -> response.getResponse().stream().map(Note::getRemoteId).collect(Collectors.toList()));
+ } else {
+ throw new UnsupportedOperationException("Used API version " + usedApiVersion + " does not support getNotesIDs().");
+ }
+ }
+
+ public Observable<ParsedResponse<Note>> getNote(long remoteId) {
+ if (ApiVersion.API_VERSION_1_0.equals(usedApiVersion)) {
+ return notesAPI_1_0.getNote(remoteId);
+ } else if (ApiVersion.API_VERSION_0_2.equals(usedApiVersion)) {
+ return notesAPI_0_2.getNote(remoteId);
+ } else {
+ throw new UnsupportedOperationException("Used API version " + usedApiVersion + " does not support getNote().");
+ }
+ }
+
public Call<Note> createNote(Note note) {
if (ApiVersion.API_VERSION_1_0.equals(usedApiVersion)) {
return notesAPI_1_0.createNote(note);
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_0_2.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_0_2.java
index fd642064..13d66c03 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_0_2.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_0_2.java
@@ -25,9 +25,15 @@ public interface NotesAPI_0_2 {
@GET("notes")
Observable<ParsedResponse<List<Note>>> getNotes(@Query("pruneBefore") long lastModified, @Header("If-None-Match") String lastETag);
+ @GET("notes?exclude=etag,readonly,content,title,category,favorite,modified")
+ Observable<ParsedResponse<List<Note>>> getNotesIDs();
+
@POST("notes")
Call<Note> createNote(@Body NotesAPI.Note_0_2 note);
+ @GET("notes/{remoteId}")
+ Observable<ParsedResponse<Note>> getNote(@Path("remoteId") long remoteId);
+
@PUT("notes/{remoteId}")
Call<Note> editNote(@Body NotesAPI.Note_0_2 note, @Path("remoteId") long remoteId);
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 dfc176c3..20f6f9a7 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
@@ -26,9 +26,15 @@ public interface NotesAPI_1_0 {
@GET("notes")
Observable<ParsedResponse<List<Note>>> getNotes(@Query("pruneBefore") long lastModified, @Header("If-None-Match") String lastETag);
+ @GET("notes?exclude=etag,readonly,content,title,category,favorite,modified")
+ Observable<ParsedResponse<List<Note>>> getNotesIDs();
+
@POST("notes")
Call<Note> createNote(@Body Note note);
+ @GET("notes/{remoteId}")
+ Observable<ParsedResponse<Note>> getNote(@Path("remoteId") long remoteId);
+
@PUT("notes/{remoteId}")
Call<Note> editNote(@Body Note note, @Path("remoteId") long remoteId);
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ImportStatus.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ImportStatus.java
new file mode 100644
index 00000000..7ae189ef
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ImportStatus.java
@@ -0,0 +1,10 @@
+package it.niedermann.owncloud.notes.shared.model;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+public class ImportStatus {
+ public int count = 0;
+ public int total = 0;
+ public final Collection<Throwable> warnings = new LinkedList<>();
+}
diff --git a/app/src/main/res/layout/activity_import_account.xml b/app/src/main/res/layout/activity_import_account.xml
index ed072796..7484a61b 100644
--- a/app/src/main/res/layout/activity_import_account.xml
+++ b/app/src/main/res/layout/activity_import_account.xml
@@ -65,12 +65,24 @@
<ProgressBar
android:id="@+id/progress_circular"
- android:layout_width="wrap_content"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/add_button"
android:layout_centerHorizontal="true"
- android:layout_marginTop="32dp"
+ android:layout_marginTop="@dimen/spacer_5x"
+ android:indeterminate="true"
android:indeterminateTint="@color/defaultBrand"
android:visibility="gone" />
+
+ <TextView
+ android:id="@+id/progress_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/progress_circular"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="@dimen/spacer_2x"
+ android:visibility="gone"
+ tools:text="@string/progress_import_indeterminate" />
</RelativeLayout>
</ScrollView> \ 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 772a57fe..693946ba 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -12,6 +12,7 @@
<string name="action_search">Search</string>
<string name="action_sorting_method">Sorting method</string>
<string name="simple_cancel">Cancel</string>
+ <string name="simple_switch">Switch</string>
<string name="simple_edit">Edit</string>
<string name="simple_remove">Remove</string>
<string name="action_edit_save">Save</string>
@@ -315,4 +316,7 @@
<string name="settings_file_suffix_description">File extension for new notes in your Nextcloud</string>
<string name="settings_file_suffix_success">New file suffix: %1$s</string>
<string name="http_status_code">HTTP status code: %1$d</string>
+ <string name="progress_import_indeterminate">Importing notes…</string>
+ <string name="progress_import">Importing note %1$d of %2$d…</string>
+ <string name="account_imported">Account imported.</string>
</resources>