package com.zhuinden.simplestackdemoexamplefragments.data.repository; import com.zhuinden.simplestackdemoexamplefragments.data.entity.DbTask; import com.zhuinden.simplestackdemoexamplefragments.data.entity.DbTaskFields; import com.zhuinden.simplestackdemoexamplefragments.presentation.mapper.TaskMapper; import com.zhuinden.simplestackdemoexamplefragments.presentation.objects.Task; import com.zhuinden.simplestackdemoexamplefragments.util.SchedulerHolder; import com.zhuinden.simplestackdemoexamplefragments.util.optional.Optional; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; import io.reactivex.Single; import io.reactivex.SingleOnSubscribe; import io.reactivex.annotations.NonNull; import io.reactivex.disposables.Disposables; import io.realm.Realm; import io.realm.RealmChangeListener; import io.realm.RealmResults; import io.realm.Sort; /** * Created by Owner on 2017. 01. 26.. */ @Singleton public class TaskRepository { @Inject TaskMapper taskMapper; @Inject @Named("LOOPER_SCHEDULER") SchedulerHolder looperScheduler; @Inject @Named("WRITE_SCHEDULER") SchedulerHolder writeScheduler; @Inject public TaskRepository() { } private List<Task> mapFrom(RealmResults<DbTask> dbTasks) { List<Task> tasks = new ArrayList<>(dbTasks.size()); for(DbTask dbTask : dbTasks) { tasks.add(taskMapper.fromRealm(dbTask)); } return tasks; } public Observable<List<Task>> getTasks() { return Observable.create((ObservableOnSubscribe<List<Task>>) emitter -> { Realm realm = Realm.getDefaultInstance(); final RealmResults<DbTask> dbTasks = realm.where(DbTask.class) .findAllSorted(DbTaskFields.ID, Sort.ASCENDING); final RealmChangeListener<RealmResults<DbTask>> realmChangeListener = element -> { if(!emitter.isDisposed()) { List<Task> tasks = mapFrom(element); if(!emitter.isDisposed()) { emitter.onNext(tasks); } } }; emitter.setDisposable(Disposables.fromAction(() -> { if(dbTasks.isValid()) { dbTasks.removeChangeListener(realmChangeListener); } realm.close(); })); dbTasks.addChangeListener(realmChangeListener); emitter.onNext(mapFrom(dbTasks)); }).subscribeOn(looperScheduler.getScheduler()).unsubscribeOn(looperScheduler.getScheduler()); } public Observable<List<Task>> getCompletedTasks() { return Observable.create((ObservableOnSubscribe<List<Task>>) emitter -> { Realm realm = Realm.getDefaultInstance(); final RealmResults<DbTask> dbTasks = realm.where(DbTask.class) .equalTo(DbTaskFields.COMPLETED, true) .findAllSorted(DbTaskFields.ID, Sort.ASCENDING); final RealmChangeListener<RealmResults<DbTask>> realmChangeListener = element -> { if(!emitter.isDisposed()) { List<Task> tasks = mapFrom(element); if(!emitter.isDisposed()) { emitter.onNext(tasks); } } }; emitter.setDisposable(Disposables.fromAction(() -> { if(dbTasks.isValid()) { dbTasks.removeChangeListener(realmChangeListener); } realm.close(); })); dbTasks.addChangeListener(realmChangeListener); emitter.onNext(mapFrom(dbTasks)); }).subscribeOn(looperScheduler.getScheduler()).unsubscribeOn(looperScheduler.getScheduler()); } public Observable<List<Task>> getActiveTasks() { return Observable.create(new ObservableOnSubscribe<List<Task>>() { @Override public void subscribe(@NonNull ObservableEmitter<List<Task>> emitter) throws Exception { Realm realm = Realm.getDefaultInstance(); final RealmResults<DbTask> dbTasks = realm.where(DbTask.class) .equalTo(DbTaskFields.COMPLETED, false) .findAllSorted(DbTaskFields.ID, Sort.ASCENDING); final RealmChangeListener<RealmResults<DbTask>> realmChangeListener = element -> { if(!emitter.isDisposed()) { List<Task> tasks = mapFrom(element); if(!emitter.isDisposed()) { emitter.onNext(tasks); } } }; emitter.setDisposable(Disposables.fromAction(() -> { if(dbTasks.isValid()) { dbTasks.removeChangeListener(realmChangeListener); } realm.close(); })); dbTasks.addChangeListener(realmChangeListener); emitter.onNext(mapFrom(dbTasks)); } }).subscribeOn(looperScheduler.getScheduler()).unsubscribeOn(looperScheduler.getScheduler()); } @SuppressWarnings("NewApi") public void insertTask(Task task) { Single.create((SingleOnSubscribe<Void>) singleSubscriber -> { try(Realm r = Realm.getDefaultInstance()) { r.executeTransaction(realm -> { realm.insertOrUpdate(taskMapper.toRealm(task)); }); } }).subscribeOn(writeScheduler.getScheduler()).subscribe(); } @SuppressWarnings("NewApi") public void insertTasks(List<Task> tasks) { Single.create((SingleOnSubscribe<Void>) singleSubscriber -> { try(Realm r = Realm.getDefaultInstance()) { List<DbTask> dbTasks = new ArrayList<>(tasks.size()); for(Task task : tasks) { dbTasks.add(taskMapper.toRealm(task)); } r.executeTransaction(realm -> { realm.insertOrUpdate(dbTasks); }); } }).subscribeOn(writeScheduler.getScheduler()).subscribe(); } @SuppressWarnings("NewApi") public void deleteCompletedTasks() { Single.create((SingleOnSubscribe<Void>) singleSubscriber -> { try(Realm r = Realm.getDefaultInstance()) { r.executeTransaction(realm -> realm.where(DbTask.class) .equalTo(DbTaskFields.COMPLETED, true) .findAll() .deleteAllFromRealm()); } }).subscribeOn(writeScheduler.getScheduler()).subscribe(); } @SuppressWarnings("NewApi") public Single<Optional<Task>> findTask(String taskId) { return Single.fromCallable(new Callable<Optional<Task>>() { @Override public Optional<Task> call() throws Exception { try(Realm realm = Realm.getDefaultInstance()) { RealmResults<DbTask> tasks = realm.where(DbTask.class).equalTo(DbTaskFields.ID, taskId).findAll(); if(tasks.size() > 0) { return Optional.of(taskMapper.fromRealm(tasks.get(0))); } else { return Optional.absent(); } } } }).subscribeOn(looperScheduler.getScheduler()); } public void setTaskCompleted(Task task) { insertTask(task.toBuilder().setCompleted(true).build()); } public void setTaskActive(Task task) { insertTask(task.toBuilder().setCompleted(false).build()); } @SuppressWarnings("NewApi") public void deleteTask(Task task) { Single.create((SingleOnSubscribe<Void>) singleSubscriber -> { try(Realm r = Realm.getDefaultInstance()) { r.executeTransaction(realm -> realm.where(DbTask.class) .equalTo(DbTaskFields.ID, task.id()) .findAll() .deleteAllFromRealm()); } }).subscribeOn(writeScheduler.getScheduler()).subscribe(); } }