Add OPML import to the account type list activity

This commit is contained in:
Shinokuni 2019-11-11 15:22:47 +01:00
parent 1f41cb974a
commit e9448c6dde
6 changed files with 144 additions and 49 deletions

View File

@ -1,36 +1,45 @@
package com.readrops.app.activities; package com.readrops.app.activities;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable; import android.os.Parcelable;
import android.util.Log;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil; import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import com.afollestad.materialdialogs.MaterialDialog;
import com.readrops.app.R; import com.readrops.app.R;
import com.readrops.app.adapters.AccountTypeListAdapter;
import com.readrops.app.database.entities.account.Account; import com.readrops.app.database.entities.account.Account;
import com.readrops.app.database.entities.account.AccountType; import com.readrops.app.database.entities.account.AccountType;
import com.readrops.app.databinding.ActivityAccountTypeListBinding; import com.readrops.app.databinding.ActivityAccountTypeListBinding;
import com.readrops.app.utils.Utils; import com.readrops.app.utils.Utils;
import com.readrops.app.viewmodels.AccountViewModel; import com.readrops.app.viewmodels.AccountViewModel;
import com.readrops.app.adapters.AccountTypeListAdapter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DisposableCompletableObserver;
import io.reactivex.observers.DisposableSingleObserver; import io.reactivex.observers.DisposableSingleObserver;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import static com.readrops.app.fragments.settings.AccountSettingsFragment.OPEN_OPML_FILE_REQUEST;
import static com.readrops.app.utils.ReadropsKeys.ACCOUNT; import static com.readrops.app.utils.ReadropsKeys.ACCOUNT;
public class AccountTypeListActivity extends AppCompatActivity { public class AccountTypeListActivity extends AppCompatActivity {
private static final String TAG = AccountTypeListActivity.class.getSimpleName();
private ActivityAccountTypeListBinding binding; private ActivityAccountTypeListBinding binding;
private AccountTypeListAdapter adapter; private AccountTypeListAdapter adapter;
private AccountViewModel viewModel; private AccountViewModel viewModel;
@ -55,7 +64,7 @@ public class AccountTypeListActivity extends AppCompatActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
adapter = new AccountTypeListAdapter(accountType -> { adapter = new AccountTypeListAdapter(accountType -> {
if (!(accountType == AccountType.LOCAL)) { if (accountType != AccountType.LOCAL) {
Intent intent = new Intent(getApplicationContext(), AddAccountActivity.class); Intent intent = new Intent(getApplicationContext(), AddAccountActivity.class);
if (fromMainActivity) if (fromMainActivity)
@ -65,8 +74,27 @@ public class AccountTypeListActivity extends AppCompatActivity {
startActivity(intent); startActivity(intent);
finish(); finish();
} else } else {
createNewLocalAccount(accountType); Account account = new Account(null, getString(AccountType.LOCAL.getName()), AccountType.LOCAL);
account.setCurrentAccount(true);
viewModel.insert(account)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableSingleObserver<Long>() {
@Override
public void onSuccess(Long id) {
account.setId(id.intValue());
goToNextActivity(account);
}
@Override
public void onError(Throwable e) {
Log.e(TAG, e.getMessage());
Utils.showSnackbar(binding.accountTypeListRoot, e.getMessage());
}
});
}
}); });
@ -84,18 +112,74 @@ public class AccountTypeListActivity extends AppCompatActivity {
return accountTypes; return accountTypes;
} }
private void createNewLocalAccount(AccountType accountType) { @Override
Account account = new Account(null, getString(accountType.getName()), accountType); public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
public void openOPMLFile(View view) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/*");
startActivityForResult(intent, OPEN_OPML_FILE_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == OPEN_OPML_FILE_REQUEST && resultCode == RESULT_OK && data != null) {
Uri uri = data.getData();
MaterialDialog dialog = new MaterialDialog.Builder(this)
.title(R.string.opml_processing)
.content(R.string.operation_takes_time)
.progress(true, 100)
.cancelable(false)
.show();
parseOPMLFile(uri, dialog);
}
super.onActivityResult(requestCode, resultCode, data);
}
private void parseOPMLFile(Uri uri, MaterialDialog dialog) {
Account account = new Account(null, getString(AccountType.LOCAL.getName()), AccountType.LOCAL);
account.setCurrentAccount(true); account.setCurrentAccount(true);
viewModel.insert(account) viewModel.insert(account)
.flatMapCompletable(id -> {
account.setId(id.intValue());
viewModel.setAccount(account);
return viewModel.parseOPMLFile(uri);
})
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableSingleObserver<Long>() { .subscribe(new DisposableCompletableObserver() {
@Override @Override
public void onSuccess(Long id) { public void onComplete() {
account.setId(id.intValue()); dialog.dismiss();
goToNextActivity(account);
}
@Override
public void onError(Throwable e) {
Log.e(TAG, e.getMessage());
dialog.dismiss();
Utils.showSnackbar(binding.accountTypeListRoot, e.getMessage());
}
});
}
private void goToNextActivity(Account account) {
if (fromMainActivity) { if (fromMainActivity) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(ACCOUNT, account); intent.putExtra(ACCOUNT, account);
@ -109,22 +193,4 @@ public class AccountTypeListActivity extends AppCompatActivity {
finish(); finish();
} }
@Override
public void onError(Throwable e) {
Utils.showSnackbar(binding.accountTypeListRoot, e.getMessage());
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
} }

View File

@ -24,13 +24,13 @@ import androidx.preference.PreferenceFragmentCompat;
import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.MaterialDialog;
import com.readrops.app.R; import com.readrops.app.R;
import com.readrops.app.ReadropsApp;
import com.readrops.app.activities.AddAccountActivity; import com.readrops.app.activities.AddAccountActivity;
import com.readrops.app.activities.ManageFeedsFoldersActivity; import com.readrops.app.activities.ManageFeedsFoldersActivity;
import com.readrops.app.database.entities.account.Account; import com.readrops.app.database.entities.account.Account;
import com.readrops.app.database.entities.account.AccountType; import com.readrops.app.database.entities.account.AccountType;
import com.readrops.app.utils.matchers.OPMLMatcher;
import com.readrops.app.ReadropsApp;
import com.readrops.app.utils.Utils; import com.readrops.app.utils.Utils;
import com.readrops.app.utils.matchers.OPMLMatcher;
import com.readrops.app.viewmodels.AccountViewModel; import com.readrops.app.viewmodels.AccountViewModel;
import com.readrops.readropslibrary.opml.OPMLParser; import com.readrops.readropslibrary.opml.OPMLParser;
import com.readrops.readropslibrary.opml.model.OPML; import com.readrops.readropslibrary.opml.model.OPML;
@ -55,7 +55,7 @@ public class AccountSettingsFragment extends PreferenceFragmentCompat {
private static final String TAG = AccountSettingsFragment.class.getSimpleName(); private static final String TAG = AccountSettingsFragment.class.getSimpleName();
private static final int OPEN_OPML_FILE_REQUEST = 1; public static final int OPEN_OPML_FILE_REQUEST = 1;
private static final int WRITE_EXTERNAL_STORAGE_REQUEST = 1; private static final int WRITE_EXTERNAL_STORAGE_REQUEST = 1;
private Account account; private Account account;
@ -192,8 +192,7 @@ public class AccountSettingsFragment extends PreferenceFragmentCompat {
} }
private void parseOPMLFile(Uri uri, MaterialDialog dialog) { private void parseOPMLFile(Uri uri, MaterialDialog dialog) {
OPMLParser.read(uri, getContext()) viewModel.parseOPMLFile(uri)
.flatMapCompletable(opml -> viewModel.insertOPMLFoldersAndFeeds(opml))
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableCompletableObserver() { .subscribe(new DisposableCompletableObserver() {

View File

@ -1,6 +1,7 @@
package com.readrops.app.viewmodels; package com.readrops.app.viewmodels;
import android.app.Application; import android.app.Application;
import android.net.Uri;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -13,7 +14,7 @@ import com.readrops.app.database.entities.account.Account;
import com.readrops.app.database.entities.account.AccountType; import com.readrops.app.database.entities.account.AccountType;
import com.readrops.app.repositories.ARepository; import com.readrops.app.repositories.ARepository;
import com.readrops.app.utils.matchers.OPMLMatcher; import com.readrops.app.utils.matchers.OPMLMatcher;
import com.readrops.readropslibrary.opml.model.OPML; import com.readrops.readropslibrary.opml.OPMLParser;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -66,13 +67,16 @@ public class AccountViewModel extends AndroidViewModel {
return database.accountDao().getAccountCount(); return database.accountDao().getAccountCount();
} }
public Completable insertOPMLFoldersAndFeeds(OPML opml) {
Map<Folder, List<Feed>> foldersAndFeeds = OPMLMatcher.INSTANCE.opmltoFoldersAndFeeds(opml);
return repository.insertOPMLFoldersAndFeeds(foldersAndFeeds);
}
public Single<Map<Folder, List<Feed>>> getFoldersWithFeeds() { public Single<Map<Folder, List<Feed>>> getFoldersWithFeeds() {
return repository.getFoldersWithFeeds(); return repository.getFoldersWithFeeds();
} }
public Completable parseOPMLFile(Uri uri) {
return OPMLParser.read(uri, getApplication())
.flatMapCompletable(opml -> {
Map<Folder, List<Feed>> foldersAndFeeds = OPMLMatcher.INSTANCE.opmltoFoldersAndFeeds(opml);
return repository.insertOPMLFoldersAndFeeds(foldersAndFeeds);
});
}
} }

View File

@ -49,6 +49,30 @@
app:layout_constraintTop_toBottomOf="@+id/account_type_list_choose" app:layout_constraintTop_toBottomOf="@+id/account_type_list_choose"
tools:itemCount="4" tools:itemCount="4"
tools:listitem="@layout/account_type_item" /> tools:listitem="@layout/account_type_item" />
<TextView
android:id="@+id/account_type_or"
style="@style/TextAppearance.AppCompat.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/or"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/account_type_recyclerview" />
<Button
android:id="@+id/account_type_opml_import"
style="@style/GenericButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/opml_import"
android:onClick="openOPMLFile"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/account_type_or" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@ -102,5 +102,6 @@
<string name="external_storage_opml_export">L\'export des soubscriptions nécessite l\'accès au stockage</string> <string name="external_storage_opml_export">L\'export des soubscriptions nécessite l\'accès au stockage</string>
<string name="try_again">Réessayer</string> <string name="try_again">Réessayer</string>
<string name="permissions">Permissions</string> <string name="permissions">Permissions</string>
<string name="or">Ou</string>
</resources> </resources>

View File

@ -111,4 +111,5 @@
<string name="external_storage_opml_export">Subscriptions export needs external storage permission</string> <string name="external_storage_opml_export">Subscriptions export needs external storage permission</string>
<string name="try_again">Try again</string> <string name="try_again">Try again</string>
<string name="permissions">Permissions</string> <string name="permissions">Permissions</string>
<string name="or">Or</string>
</resources> </resources>