From adb3476a22522a34dac13444595b162075830b83 Mon Sep 17 00:00:00 2001 From: Ahmed Date: Tue, 31 Jul 2018 02:11:32 +0200 Subject: [PATCH 1/6] Add basic data manager functionallities --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 4 +- .../blink22/android/mvpandroid/BaseApp.java | 24 +- .../android/mvpandroid/BasePresenter.java | 14 -- .../blink22/android/mvpandroid/BaseView.java | 11 - .../mvpandroid/adapters/TodosAdapter.java | 5 +- .../apiinterfaces/TodosService.java | 2 +- .../mvpandroid/data/AppDataManager.java | 146 ++++++++++++ .../android/mvpandroid/data/DataManager.java | 13 ++ .../mvpandroid/data/api/ApiEndPoint.java | 15 ++ .../mvpandroid/data/api/ApiHelper.java | 27 +++ .../mvpandroid/data/api/AppApiHelper.java | 38 ++++ .../mvpandroid/data/db/AppDbHelper.java | 138 ++++++++++++ .../android/mvpandroid/data/db/DbHelper.java | 23 ++ .../mvpandroid/data/db/model/Todo.java | 63 ++++++ .../mvpandroid/data/prefs/AppPrefsHelper.java | 30 +++ .../mvpandroid/data/prefs/PrefsHelper.java | 11 + .../mvpandroid/di/NetworkComponent.java | 42 ++-- .../android/mvpandroid/di/NetworkModule.java | 182 +++++++-------- .../android/mvpandroid/di/PerActivity.java | 15 ++ .../di/component/ActivityComponent.java | 20 ++ .../di/component/ApplicationComponent.java | 29 +++ .../mvpandroid/di/module/ActivityModule.java | 48 ++++ .../di/module/ApplicationModule.java | 146 ++++++++++++ .../mvpandroid/models/NavigationItemEnum.java | 4 +- .../android/mvpandroid/models/Todo.java | 56 ----- .../mvpandroid/network/NetworkManager.java | 106 ++++----- .../mvpandroid/network/TodosSubscriber.java | 213 +++++++++--------- .../mvpandroid/newTodo/NewTodoActivity.java | 16 -- .../mvpandroid/newTodo/NewTodoContract.java | 24 -- .../mvpandroid/newTodo/NewTodoPresenter.java | 75 ------ .../mvpandroid/todos/TodosActivity.java | 43 ---- .../mvpandroid/todos/TodosContract.java | 33 --- .../mvpandroid/todos/TodosPresenter.java | 92 -------- .../{ => ui/base}/BaseActivity.java | 18 +- .../mvpandroid/ui/base/BasePresenter.java | 54 +++++ .../mvpandroid/ui/base/IBasePresenter.java | 13 ++ .../android/mvpandroid/ui/base/IBaseView.java | 9 + .../ui/newtodo/NewTodoActivity.java | 44 ++++ .../ui/newtodo/NewTodoContract.java | 26 +++ .../newtodo}/NewTodoFragment.java | 25 +- .../ui/newtodo/NewTodoPresenter.java | 66 ++++++ .../mvpandroid/ui/todos/TodosActivity.java | 43 ++++ .../mvpandroid/ui/todos/TodosContract.java | 35 +++ .../{ => ui}/todos/TodosFragment.java | 32 +-- .../mvpandroid/ui/todos/TodosPresenter.java | 93 ++++++++ .../mvpandroid/utils/AppConstants.java | 13 ++ .../mvpandroid/viewHolders/TodosVH.java | 6 +- app/src/main/res/layout/todos_fragment.xml | 2 +- build.gradle | 2 +- 50 files changed, 1487 insertions(+), 703 deletions(-) delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/BasePresenter.java delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/BaseView.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/api/ApiEndPoint.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/api/ApiHelper.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/api/AppApiHelper.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/DbHelper.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/prefs/AppPrefsHelper.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/prefs/PrefsHelper.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/PerActivity.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/component/ActivityComponent.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/component/ApplicationComponent.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/module/ActivityModule.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/module/ApplicationModule.java delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/models/Todo.java delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoActivity.java delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoContract.java delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoPresenter.java delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/todos/TodosActivity.java delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/todos/TodosContract.java delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/todos/TodosPresenter.java rename app/src/main/java/com/blink22/android/mvpandroid/{ => ui/base}/BaseActivity.java (77%) create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/ui/base/BasePresenter.java create mode 100755 app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBasePresenter.java create mode 100755 app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBaseView.java create mode 100755 app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoActivity.java create mode 100755 app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoContract.java rename app/src/main/java/com/blink22/android/mvpandroid/{newTodo => ui/newtodo}/NewTodoFragment.java (75%) create mode 100755 app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java create mode 100755 app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosActivity.java create mode 100755 app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosContract.java rename app/src/main/java/com/blink22/android/mvpandroid/{ => ui}/todos/TodosFragment.java (73%) create mode 100755 app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/utils/AppConstants.java diff --git a/app/build.gradle b/app/build.gradle index 5eaea3b..cb5c7b7 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.application' +apply plugin: 'realm-android' android { compileSdkVersion 27 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bb72880..5774ad6 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" > - @@ -21,7 +21,7 @@ - + diff --git a/app/src/main/java/com/blink22/android/mvpandroid/BaseApp.java b/app/src/main/java/com/blink22/android/mvpandroid/BaseApp.java index a016d87..16d7027 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/BaseApp.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/BaseApp.java @@ -2,30 +2,34 @@ import android.app.Application; -import com.blink22.android.mvpandroid.di.AppModule; -import com.blink22.android.mvpandroid.di.DaggerNetworkComponent; -import com.blink22.android.mvpandroid.di.NetworkComponent; -import com.blink22.android.mvpandroid.di.NetworkModule; +import com.blink22.android.mvpandroid.data.DataManager; +import com.blink22.android.mvpandroid.di.component.ApplicationComponent; +import com.blink22.android.mvpandroid.di.component.DaggerApplicationComponent; +import com.blink22.android.mvpandroid.di.module.ApplicationModule; + +import javax.inject.Inject; /** * Created by ahmedghazy on 7/29/18. */ public class BaseApp extends Application { - NetworkComponent mNetworkComponent; + + @Inject DataManager mDataManager; + ApplicationComponent mApplicationComponent; @Override public void onCreate() { super.onCreate(); - mNetworkComponent = DaggerNetworkComponent.builder() - .appModule(new AppModule(this)) - .networkModule(new NetworkModule()) + mApplicationComponent = DaggerApplicationComponent.builder() + .applicationModule(new ApplicationModule(this)) .build(); + mApplicationComponent.inject(this); } - public NetworkComponent getNetworkComponent() { - return mNetworkComponent; + public ApplicationComponent getComponent() { + return mApplicationComponent; } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/BasePresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/BasePresenter.java deleted file mode 100755 index bcc2ca6..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/BasePresenter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.blink22.android.mvpandroid; - -import android.arch.lifecycle.LifecycleObserver; - -/** - * Created by ahmedghazy on 7/25/18. - */ - -public interface BasePresenter extends LifecycleObserver{ - - void start(); - - void stop(); -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/BaseView.java b/app/src/main/java/com/blink22/android/mvpandroid/BaseView.java deleted file mode 100755 index 99cd878..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/BaseView.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.blink22.android.mvpandroid; - -/** - * Created by ahmedghazy on 7/25/18. - */ - -public interface BaseView { - - void setPresenter(T presenter); - -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/adapters/TodosAdapter.java b/app/src/main/java/com/blink22/android/mvpandroid/adapters/TodosAdapter.java index 37f38e1..20b7532 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/adapters/TodosAdapter.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/adapters/TodosAdapter.java @@ -5,10 +5,9 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; import com.blink22.android.mvpandroid.R; -import com.blink22.android.mvpandroid.models.Todo; +import com.blink22.android.mvpandroid.data.db.model.Todo; import com.blink22.android.mvpandroid.viewHolders.TodosVH; import java.util.ArrayList; @@ -21,12 +20,10 @@ public class TodosAdapter extends RecyclerView.Adapter { private final OnItemClickListener mListener; private ArrayList mData; - private Context mContext; public TodosAdapter(Context context, ArrayList data, OnItemClickListener listener) { mData = data; mListener = listener; - mContext = context; } @Override diff --git a/app/src/main/java/com/blink22/android/mvpandroid/apiinterfaces/TodosService.java b/app/src/main/java/com/blink22/android/mvpandroid/apiinterfaces/TodosService.java index f2ec1aa..863fc1b 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/apiinterfaces/TodosService.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/apiinterfaces/TodosService.java @@ -1,6 +1,6 @@ package com.blink22.android.mvpandroid.apiinterfaces; -import com.blink22.android.mvpandroid.models.Todo; +import com.blink22.android.mvpandroid.data.db.model.Todo; import java.util.ArrayList; diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java b/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java new file mode 100644 index 0000000..e04676a --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java @@ -0,0 +1,146 @@ +package com.blink22.android.mvpandroid.data; + +import android.util.Log; + +import com.blink22.android.mvpandroid.data.api.ApiHelper; +import com.blink22.android.mvpandroid.data.db.DbHelper; +import com.blink22.android.mvpandroid.data.db.model.Todo; +import com.blink22.android.mvpandroid.data.prefs.PrefsHelper; + +import java.util.ArrayList; + +import javax.inject.Inject; + +import io.reactivex.Observable; +import io.reactivex.ObservableEmitter; +import io.reactivex.ObservableOnSubscribe; +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public class AppDataManager implements DataManager { + private ApiHelper mApiHelper; + private DbHelper mDbHelper; + private PrefsHelper mPrefsHelper; + + @Inject + public AppDataManager(ApiHelper apiHelper, DbHelper dbHelper, PrefsHelper prefsHelper) { + mApiHelper = apiHelper; + mDbHelper = dbHelper; + mPrefsHelper = prefsHelper; + } + + @Override + public String getUserName() { + return mPrefsHelper.getUserName(); + } + + @Override + public void setUserName(String userName) { + mPrefsHelper.setUserName(userName); + } + + @Override + public Observable saveTodo(Todo todo) { + + return mDbHelper.saveTodo(todo); + } + + @Override + public Observable updateTodo(int id, Todo todo) { + return mDbHelper.updateTodo(id, todo); + } + + @Override + public Observable> getTodos() { + return mDbHelper.getTodos(); +// return Observable.create(new ObservableOnSubscribe>() { +// @Override +// public void subscribe(final ObservableEmitter> emitter) throws Exception { +// mApiHelper.getTodos() +// .subscribeOn(Schedulers.io()) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribeWith(new Observer>() { +// @Override +// public void onSubscribe(Disposable d) { +// +// } +// +// @Override +// public void onNext(final ArrayList todos) { +// Log.i(AppDataManager.class.getSimpleName(), "Next"); +// mDbHelper.deleteTodos() +// .subscribeOn(Schedulers.io()) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribe(new Observer() { +// @Override +// public void onSubscribe(Disposable d) { +// +// } +// +// @Override +// public void onNext(Boolean aBoolean) { +// for (Todo todo : todos) { +// Log.i(AppDataManager.class.getSimpleName(), todo.getTitle()); +// mDbHelper.saveTodo(todo); +// } +// emitter.onNext(todos); +// } +// +// @Override +// public void onError(Throwable e) { +// emitter.onError(e); +// } +// +// @Override +// public void onComplete() { +// +// } +// }); +// } +// +// @Override +// public void onError(Throwable e) { +// Log.i(AppDataManager.class.getSimpleName(), "Errrr"); +// mDbHelper.getTodos() +// .subscribeOn(Schedulers.io()) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribe(new Observer>() { +// @Override +// public void onSubscribe(Disposable d) { +// +// } +// +// @Override +// public void onNext(ArrayList todos) { +// Log.i(AppDataManager.class.getSimpleName(), "Size of the array is" + todos.size()); +// emitter.onNext(todos); +// } +// +// @Override +// public void onError(Throwable e) { +// emitter.onError(e); +// } +// +// @Override +// public void onComplete() { +// +// } +// }); +// } +// +// @Override +// public void onComplete() { +// +// } +// }); +// } +// }); + + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java b/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java new file mode 100644 index 0000000..c517318 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java @@ -0,0 +1,13 @@ +package com.blink22.android.mvpandroid.data; + +import com.blink22.android.mvpandroid.data.api.ApiHelper; +import com.blink22.android.mvpandroid.data.db.DbHelper; +import com.blink22.android.mvpandroid.data.prefs.PrefsHelper; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public interface DataManager extends PrefsHelper, ApiHelper{ + +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/api/ApiEndPoint.java b/app/src/main/java/com/blink22/android/mvpandroid/data/api/ApiEndPoint.java new file mode 100644 index 0000000..417c6d2 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/api/ApiEndPoint.java @@ -0,0 +1,15 @@ +package com.blink22.android.mvpandroid.data.api; + +import com.blink22.android.mvpandroid.BuildConfig; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +//cannot be extended +public final class ApiEndPoint { + + public static final String TODOS = BuildConfig.BASE_URL; + + +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/api/ApiHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/api/ApiHelper.java new file mode 100644 index 0000000..3fd9f69 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/api/ApiHelper.java @@ -0,0 +1,27 @@ +package com.blink22.android.mvpandroid.data.api; + +import com.blink22.android.mvpandroid.data.db.model.Todo; + +import java.util.ArrayList; + +import io.reactivex.Observable; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Path; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public interface ApiHelper { + @GET("/todos") + Observable> getTodos(); + + @POST("/todos") + Observable saveTodo(@Body Todo todo); + + @PUT("/todos/{id}") + Observable updateTodo(@Path("id") int id, @Body Todo todo); +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/api/AppApiHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/api/AppApiHelper.java new file mode 100644 index 0000000..09cd486 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/api/AppApiHelper.java @@ -0,0 +1,38 @@ +package com.blink22.android.mvpandroid.data.api; + +import com.blink22.android.mvpandroid.data.db.model.Todo; + +import java.util.ArrayList; + +import javax.inject.Inject; + +import io.reactivex.Observable; +import retrofit2.Retrofit; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public class AppApiHelper implements ApiHelper { + ApiHelper mApiHelper; + + @Inject + public AppApiHelper(Retrofit retrofit) { + mApiHelper = retrofit.create(ApiHelper.class); + } + + @Override + public Observable> getTodos() { + return mApiHelper.getTodos(); + } + + @Override + public Observable saveTodo(Todo todo) { + return mApiHelper.saveTodo(todo); + } + + @Override + public Observable updateTodo(int id, Todo todo) { + return mApiHelper.updateTodo(id, todo); + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java new file mode 100644 index 0000000..cad40f4 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java @@ -0,0 +1,138 @@ +package com.blink22.android.mvpandroid.data.db; + +import android.arch.lifecycle.Lifecycle; +import android.arch.lifecycle.LifecycleObserver; +import android.arch.lifecycle.OnLifecycleEvent; +import android.util.Log; + +import com.blink22.android.mvpandroid.data.db.model.Todo; + +import java.util.ArrayList; + +import javax.inject.Inject; + +import io.reactivex.Observable; +import io.reactivex.ObservableEmitter; +import io.reactivex.ObservableOnSubscribe; +import io.realm.Realm; +import io.realm.RealmResults; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public class AppDbHelper implements DbHelper, LifecycleObserver { + Realm mRealm; + + @Inject + public AppDbHelper(Realm realm) { + mRealm = realm; + } + + @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) void start() { + + } + + @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) void stop() { + mRealm.close(); + } + + @Override + public Observable saveTodo(final Todo todo) { + + Observable observable = Observable.create(new ObservableOnSubscribe() { + @Override + public void subscribe(final ObservableEmitter emitter) throws Exception { + try { + final Realm currentRealm = Realm.getDefaultInstance(); + currentRealm.executeTransaction(new Realm.Transaction() { + @Override + public void execute(Realm realm) { + realm.copyToRealm(todo); + emitter.onNext(todo); + } + }); + } catch (Exception e) { + emitter.onError(e); + } + } + }); + + return observable; + } + + @Override + public Observable updateTodo(final int id, final Todo todo) { + final Observable observable = Observable.create(new ObservableOnSubscribe() { + @Override + public void subscribe(final ObservableEmitter emitter) throws Exception { + try { + final Realm currentRealm = Realm.getDefaultInstance(); + currentRealm.executeTransaction(new Realm.Transaction() { + @Override + public void execute(Realm realm) { + Todo gTodo = realm.where(Todo.class).equalTo("id", id).findFirst(); + gTodo.set(todo); + emitter.onNext(gTodo); + } + }); + } + catch (Exception e) { + emitter.onError(e); + } + } + }); + + return observable; + } + + @Override + public Observable> getTodos() { + + + Observable> observable = Observable.create(new ObservableOnSubscribe>() { + @Override + public void subscribe(final ObservableEmitter> emitter) throws Exception { + try { + final Realm currentRealm = Realm.getDefaultInstance(); + currentRealm.executeTransaction(new Realm.Transaction() { + @Override + public void execute(Realm realm) { + RealmResults realmResults = realm.where(Todo.class).findAll(); + emitter.onNext(new ArrayList(realm.copyFromRealm(realmResults))); + emitter.onComplete(); + } + }); + } catch (Exception e) { + emitter.onError(e); + } + } + }); + + return observable; + } + + @Override + public Observable deleteTodos() { + Observable observable = Observable.create(new ObservableOnSubscribe() { + @Override + public void subscribe(final ObservableEmitter emitter) throws Exception { + try { + final Realm currentRealm = Realm.getDefaultInstance(); + currentRealm.executeTransaction(new Realm.Transaction() { + @Override + public void execute(Realm realm) { + realm.delete(Todo.class); + emitter.onNext(true); + emitter.onComplete(); + } + }); + } catch (Exception e) { + emitter.onError(e); + } + } + }); + + return observable; + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/DbHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/DbHelper.java new file mode 100644 index 0000000..692608d --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/DbHelper.java @@ -0,0 +1,23 @@ +package com.blink22.android.mvpandroid.data.db; + +import com.blink22.android.mvpandroid.data.db.model.Todo; + +import java.util.ArrayList; + +import io.reactivex.Observable; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public interface DbHelper { + + Observable saveTodo(Todo todo); + + Observable updateTodo(int id, Todo todo); + + Observable> getTodos(); + + Observable deleteTodos(); + +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java new file mode 100644 index 0000000..58a12af --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java @@ -0,0 +1,63 @@ +package com.blink22.android.mvpandroid.data.db.model; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public class Todo extends RealmObject { + @PrimaryKey + private int id; + private String title; + private String description; + private boolean done; + + public void set(Todo todo) { + setTitle(todo.getTitle()); + setDescription(todo.getDescription()); + setDone(todo.isDone()); + } + + private static final AtomicInteger ai = new AtomicInteger(); + + public Todo() { + id = ai.addAndGet(1); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean isDone() { + return done; + } + + public void setDone(boolean done) { + this.done = done; + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/AppPrefsHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/AppPrefsHelper.java new file mode 100644 index 0000000..80e15e0 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/AppPrefsHelper.java @@ -0,0 +1,30 @@ +package com.blink22.android.mvpandroid.data.prefs; + +import android.content.SharedPreferences; + +import javax.inject.Inject; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public class AppPrefsHelper implements PrefsHelper { + SharedPreferences mSharedPreferences; + + private static final String PREF_KEY_USER_NAME = "PREF_KEY_USER_NAME"; + + @Inject + public AppPrefsHelper(SharedPreferences sharedPreferences) { + mSharedPreferences = sharedPreferences; + } + + @Override + public String getUserName() { + return mSharedPreferences.getString(PREF_KEY_USER_NAME, null); + } + + @Override + public void setUserName(String userName) { + mSharedPreferences.edit().putString(PREF_KEY_USER_NAME, userName).apply(); + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/PrefsHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/PrefsHelper.java new file mode 100644 index 0000000..c73dd63 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/PrefsHelper.java @@ -0,0 +1,11 @@ +package com.blink22.android.mvpandroid.data.prefs; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public interface PrefsHelper { + String getUserName(); + + void setUserName(String userName); +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkComponent.java b/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkComponent.java index 42e5e28..2ace0d9 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkComponent.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkComponent.java @@ -1,21 +1,21 @@ -package com.blink22.android.mvpandroid.di; - -import com.blink22.android.mvpandroid.newTodo.NewTodoActivity; -import com.blink22.android.mvpandroid.newTodo.NewTodoFragment; -import com.blink22.android.mvpandroid.todos.TodosActivity; -import com.blink22.android.mvpandroid.todos.TodosFragment; - -import javax.inject.Singleton; - -import dagger.Component; - -/** - * Created by ahmedghazy on 7/29/18. - */ - -@Singleton -@Component(modules={AppModule.class, NetworkModule.class}) -public interface NetworkComponent { - void inject(TodosFragment todosFragment); - void inject(NewTodoFragment newTodoFragment); -} +//package com.blink22.android.mvpandroid.di; +// +//import com.blink22.android.mvpandroid.ui.newtodo.NewTodoActivity; +//import com.blink22.android.mvpandroid.ui.newtodo.NewTodoFragment; +//import com.blink22.android.mvpandroid.ui.todos.TodosActivity; +//import com.blink22.android.mvpandroid.ui.todos.TodosFragment; +// +//import javax.inject.Singleton; +// +//import dagger.Component; +// +///** +// * Created by ahmedghazy on 7/29/18. +// */ +// +//@Singleton +//@Component(modules={AppModule.class, NetworkModule.class}) +//public interface NetworkComponent { +// void inject(TodosActivity todosActivity); +// void inject(NewTodoActivity newTodoActivity); +//} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkModule.java b/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkModule.java index 9596d74..557d1b0 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkModule.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkModule.java @@ -1,91 +1,91 @@ -package com.blink22.android.mvpandroid.di; - -import android.app.Application; - -import com.blink22.android.mvpandroid.BuildConfig; -import com.blink22.android.mvpandroid.apiinterfaces.TodosService; -import com.blink22.android.mvpandroid.network.TodosSubscriber; -import com.google.gson.Gson; - -import java.io.File; - -import javax.inject.Named; -import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; -import okhttp3.Cache; -import okhttp3.OkHttpClient; -import retrofit2.CallAdapter; -import retrofit2.Retrofit; -import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; -import retrofit2.converter.gson.GsonConverterFactory; - -/** - * Created by ahmedghazy on 7/29/18. - */ - -@Module -public class NetworkModule { - @Provides - @Named("api_url") - String provideApiLink() { - return BuildConfig.BASE_URL; - } - - @Provides - @Singleton - Cache provideOkHttpCache(Application application) { - int cacheSize = 5 * 1024 * 1024; - Cache cache = new Cache(application.getCacheDir(), cacheSize); - return cache; - } - - @Provides - @Singleton - @Named("cached") - OkHttpClient provideOkHttpClient(Cache cache) { - OkHttpClient okHttpClient = new OkHttpClient.Builder().cache(cache).build(); - return okHttpClient; - } - - @Provides - @Singleton - @Named("non_cached") - OkHttpClient provideOkHttpClientNonCached() { - OkHttpClient okHttpClient = new OkHttpClient(); - return okHttpClient; - } - - @Provides - @Singleton - @Named("rxjava2_call_adapter") - CallAdapter.Factory provideCallAdapterFactory() { - return RxJava2CallAdapterFactory.create(); - } - - @Provides - @Singleton - Retrofit provideRetrofit(@Named("cached") OkHttpClient okHttpClient, - @Named("rxjava2_call_adapter") CallAdapter.Factory rxJava2CallAdapterFactory, - @Named("api_url") String url) { - return new Retrofit.Builder() - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(rxJava2CallAdapterFactory) - .baseUrl(url) - .client(okHttpClient) - .build(); - } - - @Provides - @Singleton - TodosService provideTodosService(Retrofit retrofit) { - return retrofit.create(TodosService.class); - } - - @Provides - @Singleton - TodosSubscriber provideTodosSubscriber(TodosService todosService) { - return new TodosSubscriber(todosService); - } -} +//package com.blink22.android.mvpandroid.di; +// +//import android.app.Application; +// +//import com.blink22.android.mvpandroid.BuildConfig; +//import com.blink22.android.mvpandroid.apiinterfaces.TodosService; +//import com.blink22.android.mvpandroid.network.TodosSubscriber; +//import com.google.gson.Gson; +// +//import java.io.File; +// +//import javax.inject.Named; +//import javax.inject.Singleton; +// +//import dagger.Module; +//import dagger.Provides; +//import okhttp3.Cache; +//import okhttp3.OkHttpClient; +//import retrofit2.CallAdapter; +//import retrofit2.Retrofit; +//import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +//import retrofit2.converter.gson.GsonConverterFactory; +// +///** +// * Created by ahmedghazy on 7/29/18. +// */ +// +//@Module +//public class NetworkModule { +// @Provides +// @Named("api_url") +// String provideApiLink() { +// return BuildConfig.BASE_URL; +// } +// +// @Provides +// @Singleton +// Cache provideOkHttpCache(Application application) { +// int cacheSize = 5 * 1024 * 1024; +// Cache cache = new Cache(application.getCacheDir(), cacheSize); +// return cache; +// } +// +// @Provides +// @Singleton +// @Named("cached") +// OkHttpClient provideOkHttpClient(Cache cache) { +// OkHttpClient okHttpClient = new OkHttpClient.Builder().cache(cache).build(); +// return okHttpClient; +// } +// +// @Provides +// @Singleton +// @Named("non_cached") +// OkHttpClient provideOkHttpClientNonCached() { +// OkHttpClient okHttpClient = new OkHttpClient(); +// return okHttpClient; +// } +// +// @Provides +// @Singleton +// @Named("rxjava2_call_adapter") +// CallAdapter.Factory provideCallAdapterFactory() { +// return RxJava2CallAdapterFactory.create(); +// } +// +// @Provides +// @Singleton +// Retrofit provideRetrofit(@Named("cached") OkHttpClient okHttpClient, +// @Named("rxjava2_call_adapter") CallAdapter.Factory rxJava2CallAdapterFactory, +// @Named("api_url") String url) { +// return new Retrofit.Builder() +// .addConverterFactory(GsonConverterFactory.create()) +// .addCallAdapterFactory(rxJava2CallAdapterFactory) +// .baseUrl(url) +// .client(okHttpClient) +// .build(); +// } +// +// @Provides +// @Singleton +// TodosService provideTodosService(Retrofit retrofit) { +// return retrofit.create(TodosService.class); +// } +// +// @Provides +// @Singleton +// TodosSubscriber provideTodosSubscriber(TodosService todosService) { +// return new TodosSubscriber(todosService); +// } +//} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/PerActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/di/PerActivity.java new file mode 100644 index 0000000..8f68ffd --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/PerActivity.java @@ -0,0 +1,15 @@ +package com.blink22.android.mvpandroid.di; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Scope; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +@Scope +@Retention(RetentionPolicy.RUNTIME) +public @interface PerActivity { +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/component/ActivityComponent.java b/app/src/main/java/com/blink22/android/mvpandroid/di/component/ActivityComponent.java new file mode 100644 index 0000000..3a1d9fe --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/component/ActivityComponent.java @@ -0,0 +1,20 @@ +package com.blink22.android.mvpandroid.di.component; + +import com.blink22.android.mvpandroid.di.PerActivity; +import com.blink22.android.mvpandroid.di.module.ActivityModule; +import com.blink22.android.mvpandroid.ui.newtodo.NewTodoActivity; +import com.blink22.android.mvpandroid.ui.todos.TodosActivity; + +import dagger.Component; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +@PerActivity +@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) +public interface ActivityComponent { + void inject(TodosActivity todosActivity); + + void inject(NewTodoActivity newTodoActivity); +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/component/ApplicationComponent.java b/app/src/main/java/com/blink22/android/mvpandroid/di/component/ApplicationComponent.java new file mode 100644 index 0000000..dab8ab5 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/component/ApplicationComponent.java @@ -0,0 +1,29 @@ +package com.blink22.android.mvpandroid.di.component; + +import android.app.Application; +import android.content.Context; + +import com.blink22.android.mvpandroid.data.DataManager; +import com.blink22.android.mvpandroid.di.module.ApplicationModule; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Component; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +@Singleton +@Component(modules = ApplicationModule.class) +public interface ApplicationComponent { + void inject(Application application); + + @Named("application_context") + Context context(); + + Application application(); + + DataManager dataManager(); +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/module/ActivityModule.java b/app/src/main/java/com/blink22/android/mvpandroid/di/module/ActivityModule.java new file mode 100644 index 0000000..3bbdde0 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/module/ActivityModule.java @@ -0,0 +1,48 @@ +package com.blink22.android.mvpandroid.di.module; + +import android.content.Context; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; + +import com.blink22.android.mvpandroid.di.PerActivity; +import com.blink22.android.mvpandroid.ui.newtodo.NewTodoContract; +import com.blink22.android.mvpandroid.ui.newtodo.NewTodoPresenter; +import com.blink22.android.mvpandroid.ui.todos.TodosContract; +import com.blink22.android.mvpandroid.ui.todos.TodosPresenter; + +import javax.inject.Named; + +import dagger.Module; +import dagger.Provides; +import io.reactivex.disposables.CompositeDisposable; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +@Module +public class ActivityModule { + private AppCompatActivity mAppCompatActivity; + + public ActivityModule(AppCompatActivity appCompatActivity) { + mAppCompatActivity = appCompatActivity; + } + + @Provides + @Named("activity_context") + Context provideContext() { return mAppCompatActivity; } + + @Provides + AppCompatActivity provideActivity() { return mAppCompatActivity; } + + @Provides + CompositeDisposable provideCompositeDisposable() { return new CompositeDisposable(); } + + @Provides + @PerActivity + TodosContract.Presenter provideTodosPresenter(TodosPresenter todosPresenter) { return todosPresenter; } + + @Provides + @PerActivity + NewTodoContract.Presenter provideNewTodoPresenter(NewTodoPresenter newTodoPresenter) { return newTodoPresenter; } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/module/ApplicationModule.java b/app/src/main/java/com/blink22/android/mvpandroid/di/module/ApplicationModule.java new file mode 100644 index 0000000..8f74a33 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/module/ApplicationModule.java @@ -0,0 +1,146 @@ +package com.blink22.android.mvpandroid.di.module; + +import android.app.Application; +import android.content.Context; +import android.content.SharedPreferences; + +import com.blink22.android.mvpandroid.BuildConfig; +import com.blink22.android.mvpandroid.data.AppDataManager; +import com.blink22.android.mvpandroid.data.DataManager; +import com.blink22.android.mvpandroid.data.api.ApiEndPoint; +import com.blink22.android.mvpandroid.data.api.ApiHelper; +import com.blink22.android.mvpandroid.data.api.AppApiHelper; +import com.blink22.android.mvpandroid.data.db.AppDbHelper; +import com.blink22.android.mvpandroid.data.db.DbHelper; +import com.blink22.android.mvpandroid.data.prefs.AppPrefsHelper; +import com.blink22.android.mvpandroid.data.prefs.PrefsHelper; +import com.blink22.android.mvpandroid.utils.AppConstants; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; +import io.realm.Realm; +import okhttp3.Cache; +import okhttp3.OkHttpClient; +import retrofit2.CallAdapter; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +@Module +public class ApplicationModule { + + private final Application mApplication; + + public ApplicationModule(Application application) { + mApplication = application; + } + + @Provides + @Named("application_context") + Context provideContext() { + return mApplication; + } + + @Provides + Application provideApplication() { + return mApplication; + } + + @Provides + SharedPreferences provideSharedPreferences(@Named("shared_pref_name") String sharedPrefsName) { + return mApplication.getSharedPreferences(sharedPrefsName, Context.MODE_PRIVATE); + } + + @Provides + @Named("shared_pref_name") + String providePreferenceName() { + return AppConstants.PREF_NAME; + } + + @Provides + @Singleton + DataManager provideDataManager(AppDataManager appDataManager) { + return appDataManager; + } + + @Provides + @Singleton + ApiHelper provideApiHelper(AppApiHelper appApiHelper) { return appApiHelper; } + + @Provides + @Singleton + DbHelper provideDbHelper(AppDbHelper appDbHelper) { + return appDbHelper; + } + + @Provides + @Singleton + PrefsHelper providePreferencesHelper(AppPrefsHelper appPreferencesHelper) { + return appPreferencesHelper; + } + + + @Provides + @Named("api_url") + String provideApiLink() { + return ApiEndPoint.TODOS; + } + + @Provides + @Singleton + Cache provideOkHttpCache(Application application) { + Cache cache = new Cache(application.getCacheDir(), AppConstants.CACHE_SIZE); + return cache; + } + + @Provides + @Singleton + @Named("cached") + OkHttpClient provideOkHttpClient(Cache cache) { + OkHttpClient okHttpClient = new OkHttpClient.Builder().cache(cache).build(); + return okHttpClient; + } + + @Provides + @Singleton + @Named("non_cached") + OkHttpClient provideOkHttpClientNonCached() { + OkHttpClient okHttpClient = new OkHttpClient(); + return okHttpClient; + } + + @Provides + @Singleton + @Named("rxjava2_call_adapter") + CallAdapter.Factory provideCallAdapterFactory() { + return RxJava2CallAdapterFactory.create(); + } + + @Provides + @Singleton + Retrofit provideRetrofit(@Named("cached") OkHttpClient okHttpClient, + @Named("rxjava2_call_adapter") CallAdapter.Factory rxJava2CallAdapterFactory, + @Named("api_url") String url) { + return new Retrofit.Builder() + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(rxJava2CallAdapterFactory) + .baseUrl(url) + .client(okHttpClient) + .build(); + } + + + @Provides + @Singleton + Realm provideRealm() { + Realm.init(mApplication); + return Realm.getDefaultInstance(); + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/models/NavigationItemEnum.java b/app/src/main/java/com/blink22/android/mvpandroid/models/NavigationItemEnum.java index ace0794..d3c3ca1 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/models/NavigationItemEnum.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/models/NavigationItemEnum.java @@ -1,8 +1,8 @@ package com.blink22.android.mvpandroid.models; import com.blink22.android.mvpandroid.R; -import com.blink22.android.mvpandroid.newTodo.NewTodoActivity; -import com.blink22.android.mvpandroid.todos.TodosActivity; +import com.blink22.android.mvpandroid.ui.newtodo.NewTodoActivity; +import com.blink22.android.mvpandroid.ui.todos.TodosActivity; /** * Created by ahmedghazy on 7/26/18. diff --git a/app/src/main/java/com/blink22/android/mvpandroid/models/Todo.java b/app/src/main/java/com/blink22/android/mvpandroid/models/Todo.java deleted file mode 100755 index 401773f..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/models/Todo.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.blink22.android.mvpandroid.models; - -import android.widget.Adapter; - -import com.google.gson.annotations.SerializedName; - -/** - * Created by ahmedghazy on 7/25/18. - */ - -public class Todo{ - - @SerializedName("id") - private int id; - - @SerializedName("title") - private String title; - - @SerializedName("details") - private String details; - - @SerializedName("done") - private boolean done; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDetails() { - return details; - } - - public void setDetails(String details) { - this.details = details; - } - - public boolean isDone() { - return done; - } - - public void setDone(boolean done) { - this.done = done; - } -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/network/NetworkManager.java b/app/src/main/java/com/blink22/android/mvpandroid/network/NetworkManager.java index 8f4aac0..a59f1f6 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/network/NetworkManager.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/network/NetworkManager.java @@ -1,53 +1,53 @@ -package com.blink22.android.mvpandroid.network; - -import com.blink22.android.mvpandroid.BuildConfig; -import com.blink22.android.mvpandroid.apiinterfaces.TodosService; - -import java.io.IOException; - -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import retrofit2.Retrofit; -import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; -import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; -import retrofit2.converter.gson.GsonConverterFactory; -import retrofit2.converter.scalars.ScalarsConverterFactory; - -/** - * Created by ahmedghazy on 7/25/18. - */ - -public class NetworkManager { - private static final String TAG = NetworkManager.class.getSimpleName(); - - private static NetworkManager sNetworkManager; - - private TodosService mTodosService; - - private NetworkManager() { - // Required private constructor for singleton class - } - - public static NetworkManager getInstance() { - if (sNetworkManager == null) { - sNetworkManager = new NetworkManager(); - } - - return sNetworkManager; - } - - public TodosService getTodosService() { - if (mTodosService == null) { - mTodosService = new Retrofit - .Builder() - .baseUrl(BuildConfig.BASE_URL) - .addConverterFactory(GsonConverterFactory.create()) - .addConverterFactory(ScalarsConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .build() - .create(TodosService.class); - } - return mTodosService; - } -} +//package com.blink22.android.mvpandroid.network; +// +//import com.blink22.android.mvpandroid.BuildConfig; +//import com.blink22.android.mvpandroid.apiinterfaces.TodosService; +// +//import java.io.IOException; +// +//import okhttp3.Interceptor; +//import okhttp3.OkHttpClient; +//import okhttp3.Request; +//import retrofit2.Retrofit; +//import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; +//import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +//import retrofit2.converter.gson.GsonConverterFactory; +//import retrofit2.converter.scalars.ScalarsConverterFactory; +// +///** +// * Created by ahmedghazy on 7/25/18. +// */ +// +//public class NetworkManager { +// private static final String TAG = NetworkManager.class.getSimpleName(); +// +// private static NetworkManager sNetworkManager; +// +// private TodosService mTodosService; +// +// private NetworkManager() { +// // Required private constructor for singleton class +// } +// +// public static NetworkManager getInstance() { +// if (sNetworkManager == null) { +// sNetworkManager = new NetworkManager(); +// } +// +// return sNetworkManager; +// } +// +// public TodosService getTodosService() { +// if (mTodosService == null) { +// mTodosService = new Retrofit +// .Builder() +// .baseUrl(BuildConfig.BASE_URL) +// .addConverterFactory(GsonConverterFactory.create()) +// .addConverterFactory(ScalarsConverterFactory.create()) +// .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) +// .build() +// .create(TodosService.class); +// } +// return mTodosService; +// } +//} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/network/TodosSubscriber.java b/app/src/main/java/com/blink22/android/mvpandroid/network/TodosSubscriber.java index d90da3e..142ae82 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/network/TodosSubscriber.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/network/TodosSubscriber.java @@ -1,108 +1,105 @@ -package com.blink22.android.mvpandroid.network; - -import com.blink22.android.mvpandroid.apiinterfaces.TodosService; -import com.blink22.android.mvpandroid.models.Todo; - -import java.util.ArrayList; - -import io.reactivex.Observable; -import io.reactivex.Observer; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.observers.DisposableObserver; -import io.reactivex.schedulers.Schedulers; - -/** - * Created by ahmedghazy on 7/26/18. - */ - -public class TodosSubscriber { - - private static final String TAG = TodosSubscriber.class.getSimpleName(); - - private final TodosService mTodosService; - - public TodosSubscriber(TodosService todosService) { - mTodosService = todosService; - } - - public DisposableObserver> getTodos(final Callback> callback) { - - return mTodosService - .getTodos() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(new DisposableObserver>() { - @Override - public void onNext(ArrayList todos) { - callback.onSuccess(todos); - } - - @Override - public void onError(Throwable e) { - callback.onError(new Exception(e)); - } - - @Override - public void onComplete() { - - } - }); - } - - public DisposableObserver createTodo(final Callback callback, Todo todo) { - - return mTodosService - .createTodo(todo) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(new DisposableObserver() { - @Override - public void onNext(Todo todo) { - callback.onSuccess(todo); - } - - @Override - public void onError(Throwable e) { - callback.onError(new Exception(e)); - } - - @Override - public void onComplete() { - - } - }); - } - - public DisposableObserver updateTodo(final Callback callback, Todo todo) { - - return mTodosService - .updateTodo(todo.getId(), todo) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(new DisposableObserver() { - @Override - public void onNext(Todo todo) { - callback.onSuccess(todo); - } - - @Override - public void onError(Throwable e) { - callback.onError(new Exception(e)); - } - - @Override - public void onComplete() { - - } - }); - } - - public interface Callback { - void onSuccess(T ret); - - // Investigate what kind of exception - void onError(Exception e); - } - -} +//package com.blink22.android.mvpandroid.network; +// +//import com.blink22.android.mvpandroid.apiinterfaces.TodosService; +//import com.blink22.android.mvpandroid.data.db.model.Todo; +// +//import java.util.ArrayList; +// +//import io.reactivex.android.schedulers.AndroidSchedulers; +//import io.reactivex.observers.DisposableObserver; +//import io.reactivex.schedulers.Schedulers; +// +///** +// * Created by ahmedghazy on 7/26/18. +// */ +// +//public class TodosSubscriber { +// +// private static final String TAG = TodosSubscriber.class.getSimpleName(); +// +// private final TodosService mTodosService; +// +// public TodosSubscriber(TodosService todosService) { +// mTodosService = todosService; +// } +// +// public DisposableObserver> getTodos(final Callback> callback) { +// +// return mTodosService +// .getTodos() +// .subscribeOn(Schedulers.io()) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribeWith(new DisposableObserver>() { +// @Override +// public void onNext(ArrayList todos) { +// callback.onSuccess(todos); +// } +// +// @Override +// public void onError(Throwable e) { +// callback.onError(new Exception(e)); +// } +// +// @Override +// public void onComplete() { +// +// } +// }); +// } +// +// public DisposableObserver createTodo(final Callback callback, Todo todo) { +// +// return mTodosService +// .createTodo(todo) +// .subscribeOn(Schedulers.io()) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribeWith(new DisposableObserver() { +// @Override +// public void onNext(Todo todo) { +// callback.onSuccess(todo); +// } +// +// @Override +// public void onError(Throwable e) { +// callback.onError(new Exception(e)); +// } +// +// @Override +// public void onComplete() { +// +// } +// }); +// } +// +// public DisposableObserver updateTodo(final Callback callback, Todo todo) { +// +// return mTodosService +// .updateTodo(todo.getId(), todo) +// .subscribeOn(Schedulers.io()) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribeWith(new DisposableObserver() { +// @Override +// public void onNext(Todo todo) { +// callback.onSuccess(todo); +// } +// +// @Override +// public void onError(Throwable e) { +// callback.onError(new Exception(e)); +// } +// +// @Override +// public void onComplete() { +// +// } +// }); +// } +// +// public interface Callback { +// void onSuccess(T ret); +// +// // Investigate what kind of exception +// void onError(Exception e); +// } +// +//} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoActivity.java deleted file mode 100755 index 4f357d9..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoActivity.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.blink22.android.mvpandroid.newTodo; - -import android.support.v4.app.Fragment; - -import com.blink22.android.mvpandroid.BaseActivity; - -/** - * Created by ahmedghazy on 7/26/18. - */ - -public class NewTodoActivity extends BaseActivity { - @Override - protected Fragment createFragment() { - return NewTodoFragment.newInstance(); - } -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoContract.java b/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoContract.java deleted file mode 100755 index 8d91b8d..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoContract.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.blink22.android.mvpandroid.newTodo; - -import com.blink22.android.mvpandroid.BasePresenter; -import com.blink22.android.mvpandroid.BaseView; - -/** - * Created by ahmedghazy on 7/26/18. - */ - -public interface NewTodoContract { - interface View extends BaseView { - - String getTitle(); - String getDescription(); - void terminate(); - - } - - interface Presenter extends BasePresenter { - - public void createTodo(); - - } -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoPresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoPresenter.java deleted file mode 100755 index 2868697..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoPresenter.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.blink22.android.mvpandroid.newTodo; - -import android.arch.lifecycle.Lifecycle; -import android.arch.lifecycle.OnLifecycleEvent; -import android.util.Log; - -import com.blink22.android.mvpandroid.models.Todo; -import com.blink22.android.mvpandroid.network.TodosSubscriber; -import com.blink22.android.mvpandroid.todos.TodosContract; -import com.blink22.android.mvpandroid.todos.TodosPresenter; - -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.observers.DisposableObserver; -import rx.Subscription; -import rx.subscriptions.CompositeSubscription; - -/** - * Created by ahmedghazy on 7/26/18. - */ - -public class NewTodoPresenter implements NewTodoContract.Presenter { - private static final String TAG = TodosPresenter.class.getSimpleName(); - private static NewTodoPresenter sNewTodoPresenter; - - private final TodosSubscriber mTodosSubscriber; - private final NewTodoContract.View mView; - private CompositeDisposable mCompositeDisposable; - - public static NewTodoPresenter getInstance(TodosSubscriber todosSubscriber, NewTodoContract.View view) { - return sNewTodoPresenter == null ? new NewTodoPresenter(todosSubscriber, view) : sNewTodoPresenter; - } - - private NewTodoPresenter(TodosSubscriber todosSubscriber, NewTodoContract.View view) { - - this.mTodosSubscriber = todosSubscriber; - this.mView = view; - - } - - @Override - @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) - public void start() { - this.mCompositeDisposable = new CompositeDisposable(); - } - - @Override - @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) - public void stop() { - mCompositeDisposable.dispose(); - } - - @Override - public void createTodo() { - - Todo todo = new Todo(); - todo.setTitle(mView.getTitle()); - todo.setDetails(mView.getDescription()); - - DisposableObserver disposableObserver = mTodosSubscriber.createTodo(new TodosSubscriber.Callback() { - @Override - public void onSuccess(Todo todo) { - mView.terminate(); - } - - @Override - public void onError(Exception e) { - - } - - }, todo); - - mCompositeDisposable.add(disposableObserver); - - } -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosActivity.java deleted file mode 100755 index a7da693..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosActivity.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.blink22.android.mvpandroid.todos; - -import android.os.Bundle; -import android.os.PersistableBundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.View; -import android.widget.ProgressBar; -import android.widget.Toast; - -import com.blink22.android.mvpandroid.BaseApp; -import com.blink22.android.mvpandroid.BaseActivity; -import com.blink22.android.mvpandroid.adapters.TodosAdapter; -import com.blink22.android.mvpandroid.models.Todo; - -import java.util.ArrayList; - -import com.blink22.android.mvpandroid.R; -import com.blink22.android.mvpandroid.network.NetworkManager; -import com.blink22.android.mvpandroid.network.TodosSubscriber; - -import butterknife.BindView; -import butterknife.ButterKnife; - -/** - * Created by ahmedghazy on 7/25/18. - */ - -public class TodosActivity extends BaseActivity{ - - @Override - protected Fragment createFragment() { - return TodosFragment.newInstance(); - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosContract.java b/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosContract.java deleted file mode 100755 index 1b84f21..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosContract.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.blink22.android.mvpandroid.todos; - -import com.blink22.android.mvpandroid.BasePresenter; -import com.blink22.android.mvpandroid.BaseView; -import com.blink22.android.mvpandroid.models.Todo; - -import java.util.ArrayList; - -/** - * Created by ahmedghazy on 7/25/18. - */ - -public interface TodosContract { - interface View extends BaseView { - - void showWait(); - - void removeWait(); - - void onFailure(String appErrorMessage); - - void onGetTodosSuccess(ArrayList todos); - - } - - interface Presenter extends BasePresenter { - - void getTodos(); - - void updateTodo(Todo todo); - - } -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosPresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosPresenter.java deleted file mode 100755 index 49e4b2e..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosPresenter.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.blink22.android.mvpandroid.todos; - -import android.arch.lifecycle.Lifecycle; -import android.arch.lifecycle.LifecycleObserver; -import android.arch.lifecycle.OnLifecycleEvent; - -import com.blink22.android.mvpandroid.models.Todo; -import com.blink22.android.mvpandroid.network.TodosSubscriber; - -import java.util.ArrayList; - -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.observers.DisposableObserver; - -/** - * Created by ahmedghazy on 7/25/18. - */ - -public class TodosPresenter implements TodosContract.Presenter { - private static final String TAG = TodosPresenter.class.getSimpleName(); - private static TodosPresenter sTodosPresenter; - - private final TodosSubscriber mTodosSubscriber; - private final TodosContract.View mView; - private CompositeDisposable mCompositeDisposable; - private ArrayList mTodos; - - public static TodosPresenter getInstance(TodosSubscriber todosSubscriber, TodosContract.View view) { - return sTodosPresenter == null ? new TodosPresenter(todosSubscriber, view) : sTodosPresenter; - } - - private TodosPresenter(TodosSubscriber todosSubscriber, TodosContract.View view) { - - this.mTodosSubscriber = todosSubscriber; - this.mView = view; - - } - - @Override - @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) public void start() { - this.mCompositeDisposable = new CompositeDisposable(); - } - - @Override - @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) public void stop() { - mCompositeDisposable.dispose(); - } - - @Override - public void getTodos() { - - mView.showWait(); - - DisposableObserver> disposableObserver = mTodosSubscriber.getTodos(new TodosSubscriber.Callback>() { - @Override - public void onSuccess(ArrayList todos) { - mView.removeWait(); - mTodos = todos; - mView.onGetTodosSuccess(todos); - } - - @Override - public void onError(Exception networkError) { - mView.removeWait(); - mView.onFailure(networkError.getMessage()); - } - - }); - - mCompositeDisposable.add(disposableObserver); - } - - @Override - public void updateTodo(Todo todo) { - todo.setDone(!todo.isDone()); - - DisposableObserver disposableObserver = mTodosSubscriber.updateTodo(new TodosSubscriber.Callback() { - @Override - public void onSuccess(Todo todo) { - - } - - @Override - public void onError(Exception networkError) { - - } - - }, todo); - - mCompositeDisposable.add(disposableObserver); - } -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/BaseActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java similarity index 77% rename from app/src/main/java/com/blink22/android/mvpandroid/BaseActivity.java rename to app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java index 5501ec7..e1a6e91 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/BaseActivity.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java @@ -1,4 +1,4 @@ -package com.blink22.android.mvpandroid; +package com.blink22.android.mvpandroid.ui.base; import android.content.Intent; import android.os.Bundle; @@ -12,7 +12,11 @@ import android.view.Menu; import android.view.MenuItem; +import com.blink22.android.mvpandroid.BaseApp; import com.blink22.android.mvpandroid.R; +import com.blink22.android.mvpandroid.di.component.ActivityComponent; +import com.blink22.android.mvpandroid.di.component.DaggerActivityComponent; +import com.blink22.android.mvpandroid.di.module.ActivityModule; import com.blink22.android.mvpandroid.models.NavigationItemEnum; import butterknife.BindView; @@ -27,9 +31,21 @@ public abstract class BaseActivity extends AppCompatActivity implements Navigati @BindView(R.id.drawer_layout) DrawerLayout mDrawerLayout; @BindView(R.id.nav_view) NavigationView navigationView; + public ActivityComponent getActivityComponent() { + return mActivityComponent; + } + + private ActivityComponent mActivityComponent; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + mActivityComponent = DaggerActivityComponent.builder() + .applicationComponent(((BaseApp) getApplication()).getComponent()) + .activityModule(new ActivityModule(this)) + .build(); + setContentView(R.layout.activity_fragment); ButterKnife.bind(this); diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BasePresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BasePresenter.java new file mode 100644 index 0000000..04b39ca --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BasePresenter.java @@ -0,0 +1,54 @@ +package com.blink22.android.mvpandroid.ui.base; + +import android.arch.lifecycle.Lifecycle; +import android.arch.lifecycle.LifecycleObserver; +import android.arch.lifecycle.OnLifecycleEvent; + +import com.blink22.android.mvpandroid.data.DataManager; + +import javax.inject.Inject; + +import io.reactivex.disposables.CompositeDisposable; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public class BasePresenter implements IBasePresenter, LifecycleObserver { + + private final DataManager mDataManager; + private final CompositeDisposable mCompositeDisposable; + private V mView; + + @Inject + public BasePresenter(DataManager dataManager, CompositeDisposable compositeDisposable) { + mDataManager = dataManager; + mCompositeDisposable = compositeDisposable; + } + + public DataManager getDataManager() { + return mDataManager; + } + + public CompositeDisposable getCompositeDisposable() { + return mCompositeDisposable; + } + + public V getView() { + return mView; + } + + public void onAttach(V view) { + mView = view; + } + + @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) + public void onCreate() { + + } + + @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) + public void onDestroy() { + mCompositeDisposable.dispose(); + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBasePresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBasePresenter.java new file mode 100755 index 0000000..3a5375e --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBasePresenter.java @@ -0,0 +1,13 @@ +package com.blink22.android.mvpandroid.ui.base; + +import android.arch.lifecycle.LifecycleObserver; + +/** + * Created by ahmedghazy on 7/25/18. + */ + +public interface IBasePresenter extends LifecycleObserver{ + + public void onAttach(V view); + +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBaseView.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBaseView.java new file mode 100755 index 0000000..149d553 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBaseView.java @@ -0,0 +1,9 @@ +package com.blink22.android.mvpandroid.ui.base; + +/** + * Created by ahmedghazy on 7/25/18. + */ + +public interface IBaseView { + +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoActivity.java new file mode 100755 index 0000000..730196b --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoActivity.java @@ -0,0 +1,44 @@ +package com.blink22.android.mvpandroid.ui.newtodo; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; + +import com.blink22.android.mvpandroid.ui.base.BaseActivity; + +import javax.inject.Inject; + +/** + * Created by ahmedghazy on 7/26/18. + */ + +public class NewTodoActivity extends BaseActivity { + + @Inject + NewTodoContract.Presenter mPresenter; + + @Override + protected Fragment createFragment() { + return NewTodoFragment.newInstance(); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getActivityComponent().inject(this); + + getLifecycle().addObserver(mPresenter); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + getLifecycle().removeObserver(mPresenter); + } + + public NewTodoContract.Presenter getPresenter() { + return mPresenter; + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoContract.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoContract.java new file mode 100755 index 0000000..48f64d0 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoContract.java @@ -0,0 +1,26 @@ +package com.blink22.android.mvpandroid.ui.newtodo; + +import com.blink22.android.mvpandroid.di.PerActivity; +import com.blink22.android.mvpandroid.ui.base.IBasePresenter; +import com.blink22.android.mvpandroid.ui.base.IBaseView; + +/** + * Created by ahmedghazy on 7/26/18. + */ + +public interface NewTodoContract { + interface View extends IBaseView { + + String getTitle(); + String getDescription(); + void terminate(); + + } + + @PerActivity + interface Presenter extends IBasePresenter { + + public void createTodo(); + + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoFragment.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java similarity index 75% rename from app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoFragment.java rename to app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java index 99c6e56..08b2451 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/newTodo/NewTodoFragment.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java @@ -1,4 +1,4 @@ -package com.blink22.android.mvpandroid.newTodo; +package com.blink22.android.mvpandroid.ui.newtodo; import android.os.Bundle; import android.support.annotation.NonNull; @@ -11,10 +11,9 @@ import android.widget.Button; import android.widget.TextView; -import com.blink22.android.mvpandroid.BaseApp; import com.blink22.android.mvpandroid.R; -import com.blink22.android.mvpandroid.network.NetworkManager; -import com.blink22.android.mvpandroid.network.TodosSubscriber; +import com.blink22.android.mvpandroid.ui.base.BaseActivity; +import com.blink22.android.mvpandroid.ui.todos.TodosActivity; import javax.inject.Inject; @@ -35,8 +34,6 @@ public class NewTodoFragment extends Fragment implements NewTodoContract.View { TextView mDescription; @BindView(R.id.new_todo_submit) Button mSubmit; - NewTodoContract.Presenter mPresenter; - @Inject TodosSubscriber mTodosSubscriber; public static NewTodoFragment newInstance() { @@ -50,22 +47,11 @@ public static NewTodoFragment newInstance() { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - ((BaseApp) getActivity().getApplication()).getNetworkComponent().inject(this); - - setPresenter(NewTodoPresenter.getInstance(mTodosSubscriber, this)); - getLifecycle().addObserver(mPresenter); - } - - @Override - public void setPresenter(NewTodoContract.Presenter presenter) { - mPresenter = presenter; } @Override public void onDestroy() { super.onDestroy(); - getLifecycle().removeObserver(mPresenter); } @Nullable @@ -75,10 +61,13 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c super.onCreateView(inflater, container, savedInstanceState); View v = inflater.inflate(R.layout.fragment_new_todo, container, false); ButterKnife.bind(this, v); + + ((NewTodoActivity) getActivity()).getPresenter().onAttach(this); + mSubmit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mPresenter.createTodo(); + ((NewTodoActivity) getActivity()).getPresenter().createTodo(); } }); return v; diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java new file mode 100755 index 0000000..a3bd632 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java @@ -0,0 +1,66 @@ +package com.blink22.android.mvpandroid.ui.newtodo; + +import android.arch.lifecycle.Lifecycle; +import android.arch.lifecycle.OnLifecycleEvent; + +import com.blink22.android.mvpandroid.data.DataManager; +import com.blink22.android.mvpandroid.data.db.model.Todo; +import com.blink22.android.mvpandroid.ui.base.BasePresenter; +import com.blink22.android.mvpandroid.ui.todos.TodosPresenter; + +import javax.inject.Inject; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.observers.DisposableObserver; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by ahmedghazy on 7/26/18. + */ + +public class NewTodoPresenter extends BasePresenter + implements NewTodoContract.Presenter { + private static final String TAG = TodosPresenter.class.getSimpleName(); + + @Inject + public NewTodoPresenter(DataManager dataManager, CompositeDisposable compositeDisposable) { + super(dataManager,compositeDisposable); + } + + @Override + public void createTodo() { + + Todo todo = new Todo(); + todo.setTitle(getView().getTitle()); + todo.setDescription(getView().getDescription()); + + getCompositeDisposable().add( getDataManager().saveTodo(todo).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribeWith(new DisposableObserver() { + @Override + public void onNext(Todo todo) { + getView().terminate(); + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + + } + }) ); + + } + + @Override + public void onCreate() { + + } + + @Override + public void onDestroy() { + + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosActivity.java new file mode 100755 index 0000000..8d40124 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosActivity.java @@ -0,0 +1,43 @@ +package com.blink22.android.mvpandroid.ui.todos; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; + +import com.blink22.android.mvpandroid.BaseApp; +import com.blink22.android.mvpandroid.ui.base.BaseActivity; + +import javax.inject.Inject; + +/** + * Created by ahmedghazy on 7/25/18. + */ + +public class TodosActivity extends BaseActivity{ + @Inject TodosContract.Presenter mPresenter; + + @Override + protected Fragment createFragment() { + return TodosFragment.newInstance(); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getActivityComponent().inject(this); + + getLifecycle().addObserver(mPresenter); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + getLifecycle().removeObserver(mPresenter); + } + + public TodosContract.Presenter getPresenter() { + return mPresenter; + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosContract.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosContract.java new file mode 100755 index 0000000..9d536a6 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosContract.java @@ -0,0 +1,35 @@ +package com.blink22.android.mvpandroid.ui.todos; + +import com.blink22.android.mvpandroid.data.db.model.Todo; +import com.blink22.android.mvpandroid.di.PerActivity; +import com.blink22.android.mvpandroid.ui.base.IBasePresenter; +import com.blink22.android.mvpandroid.ui.base.IBaseView; + +import java.util.ArrayList; + +/** + * Created by ahmedghazy on 7/25/18. + */ + +public interface TodosContract { + interface View extends IBaseView { + + void showWait(); + + void removeWait(); + + void onFailure(String appErrorMessage); + + void onGetTodosSuccess(ArrayList todos); + + } + + @PerActivity + interface Presenter extends IBasePresenter { + + void getTodos(); + + void updateTodo(Todo todo); + + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosFragment.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java similarity index 73% rename from app/src/main/java/com/blink22/android/mvpandroid/todos/TodosFragment.java rename to app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java index 7cc1832..3eb65cd 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/todos/TodosFragment.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java @@ -1,29 +1,25 @@ -package com.blink22.android.mvpandroid.todos; +package com.blink22.android.mvpandroid.ui.todos; import android.os.Bundle; -import android.os.PersistableBundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; -import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.Toast; -import com.blink22.android.mvpandroid.BaseApp; -import com.blink22.android.mvpandroid.BaseActivity; import com.blink22.android.mvpandroid.adapters.TodosAdapter; -import com.blink22.android.mvpandroid.models.Todo; import java.util.ArrayList; import com.blink22.android.mvpandroid.R; -import com.blink22.android.mvpandroid.network.NetworkManager; -import com.blink22.android.mvpandroid.network.TodosSubscriber; +import com.blink22.android.mvpandroid.data.db.model.Todo; +import com.blink22.android.mvpandroid.ui.base.BaseActivity; import javax.inject.Inject; @@ -37,8 +33,6 @@ public class TodosFragment extends Fragment implements TodosContract.View { @BindView(R.id.todos_list) RecyclerView mTodos; @BindView(R.id.todos_progress) ProgressBar mProgressBar; - TodosContract.Presenter mTodosPresenter; - @Inject TodosSubscriber mTodosSubscriber; public static TodosFragment newInstance() { @@ -55,10 +49,6 @@ public static TodosFragment newInstance() { public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ((BaseApp) getActivity().getApplication()).getNetworkComponent().inject(this); - - setPresenter(TodosPresenter.getInstance(mTodosSubscriber, this)); - getLifecycle().addObserver(mTodosPresenter); } @Nullable @@ -69,6 +59,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c ButterKnife.bind(this, v); + ((TodosActivity) getActivity()).getPresenter().onAttach(this); + mTodos.setLayoutManager(new LinearLayoutManager(getActivity())); return v; @@ -77,13 +69,12 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c @Override public void onResume() { super.onResume(); - mTodosPresenter.getTodos(); + ((TodosActivity) getActivity()).getPresenter().getTodos(); } @Override public void onDestroy() { super.onDestroy(); - getLifecycle().removeObserver(mTodosPresenter); } @Override @@ -104,19 +95,16 @@ public void onFailure(String appErrorMessage) { @Override public void onGetTodosSuccess(ArrayList todos) { + Log.i(TAG, "here"); + Log.i(TAG, todos.size() + ""); TodosAdapter adapter = new TodosAdapter(getActivity().getApplicationContext(), todos, new TodosAdapter.OnItemClickListener() { @Override public void onClick(Todo item) { - mTodosPresenter.updateTodo(item); + ((TodosActivity) getActivity()).getPresenter().updateTodo(item); } }); mTodos.setAdapter(adapter); } - - @Override - public void setPresenter(TodosContract.Presenter presenter) { - mTodosPresenter = presenter; - } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java new file mode 100755 index 0000000..6f48921 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java @@ -0,0 +1,93 @@ +package com.blink22.android.mvpandroid.ui.todos; + +import android.util.Log; + +import com.blink22.android.mvpandroid.data.DataManager; +import com.blink22.android.mvpandroid.data.db.model.Todo; +import com.blink22.android.mvpandroid.ui.base.BasePresenter; + +import java.util.ArrayList; +import java.util.Observable; +import java.util.Observer; + +import javax.inject.Inject; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.observers.DisposableObserver; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by ahmedghazy on 7/25/18. + */ + +public class TodosPresenter extends BasePresenter + implements TodosContract.Presenter { + private static final String TAG = TodosPresenter.class.getSimpleName(); + + @Inject + public TodosPresenter(DataManager dataManager, CompositeDisposable compositeDisposable) { + super(dataManager, compositeDisposable); + } + + @Override + public void getTodos() { + + getView().showWait(); + + + getCompositeDisposable().add(getDataManager() + .getTodos() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(new DisposableObserver>() { + @Override + public void onNext(ArrayList todos) { + getView().onGetTodosSuccess(todos); + getView().removeWait(); + } + + @Override + public void onError(Throwable e) { + getView().onFailure(e.getMessage()); + Log.i(TAG, e.getLocalizedMessage()); + } + + @Override + public void onComplete() { + + } + } + ) + ); + } + + @Override + public void updateTodo(Todo todo) { + todo.setDone(!todo.isDone()); + + getCompositeDisposable().add( getDataManager() + .updateTodo(todo.getId(), todo) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(new DisposableObserver( + + ) { + @Override + public void onNext(Todo todo) { + + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + + } + })); + } + +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/utils/AppConstants.java b/app/src/main/java/com/blink22/android/mvpandroid/utils/AppConstants.java new file mode 100644 index 0000000..015ae16 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/utils/AppConstants.java @@ -0,0 +1,13 @@ +package com.blink22.android.mvpandroid.utils; + +/** + * Created by ahmedghazy on 7/30/18. + */ + +public final class AppConstants { + + public static final String PREF_NAME = "todos_pref"; + + public static final int CACHE_SIZE = 5 * 1024 * 1024; + +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/viewHolders/TodosVH.java b/app/src/main/java/com/blink22/android/mvpandroid/viewHolders/TodosVH.java index 6903d1c..3913662 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/viewHolders/TodosVH.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/viewHolders/TodosVH.java @@ -1,9 +1,7 @@ package com.blink22.android.mvpandroid.viewHolders; import android.support.v7.widget.RecyclerView; -import android.util.Log; import android.view.View; -import android.widget.AdapterView; import android.widget.CheckBox; import android.widget.TextView; @@ -12,7 +10,7 @@ import com.blink22.android.mvpandroid.R; import com.blink22.android.mvpandroid.adapters.TodosAdapter; -import com.blink22.android.mvpandroid.models.Todo; +import com.blink22.android.mvpandroid.data.db.model.Todo; /** * Created by ahmedghazy on 7/25/18. @@ -31,7 +29,7 @@ public TodosVH(View itemView) { public void bind(final Todo todo, final TodosAdapter.OnItemClickListener listener) { mTitle.setText(todo.getTitle()); - mDescription.setText(todo.getDetails()); + mDescription.setText(todo.getDescription()); mDone.setChecked(todo.isDone()); mDone.setOnClickListener(new View.OnClickListener() { diff --git a/app/src/main/res/layout/todos_fragment.xml b/app/src/main/res/layout/todos_fragment.xml index 259da92..6284738 100755 --- a/app/src/main/res/layout/todos_fragment.xml +++ b/app/src/main/res/layout/todos_fragment.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="todos.TodosActivity"> + tools:context=".ui.todos.TodosActivity"> Date: Tue, 31 Jul 2018 16:20:08 +0200 Subject: [PATCH 2/6] Add sync adapter with content provider --- app/src/main/AndroidManifest.xml | 35 +++ .../mvpandroid/data/AppDataManager.java | 87 +----- .../android/mvpandroid/data/DataManager.java | 7 + .../data/db/AccountAuthenticator.java | 56 ++++ .../mvpandroid/data/db/AccountGeneral.java | 69 +++++ .../data/db/AuthenticatorService.java | 31 ++ .../mvpandroid/data/db/CleanupJobService.java | 47 +++ .../mvpandroid/data/db/DatabaseContract.java | 56 ++++ .../mvpandroid/data/db/SyncAdapter.java | 261 ++++++++++++++++ .../mvpandroid/data/db/SyncService.java | 38 +++ .../mvpandroid/data/db/TodoProvider.java | 280 ++++++++++++++++++ .../mvpandroid/data/db/model/Todo.java | 4 + .../android/mvpandroid/di/PerSyncService.java | 15 + .../di/component/SyncAdapterComponent.java | 19 ++ .../di/module/SyncAdapterModule.java | 24 ++ .../mvpandroid/ui/base/BaseActivity.java | 59 ++++ app/src/main/res/xml/authenticator.xml | 8 + app/src/main/res/xml/syncadapter.xml | 9 + app/src/main/res/xml/syncsettings.xml | 8 + 19 files changed, 1031 insertions(+), 82 deletions(-) create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountAuthenticator.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountGeneral.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/AuthenticatorService.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/CleanupJobService.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/DatabaseContract.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncAdapter.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncService.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/TodoProvider.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/PerSyncService.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/component/SyncAdapterComponent.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/module/SyncAdapterModule.java create mode 100644 app/src/main/res/xml/authenticator.xml create mode 100644 app/src/main/res/xml/syncadapter.xml create mode 100644 app/src/main/res/xml/syncsettings.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5774ad6..66c4509 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,13 @@ package="com.blink22.android.mvpandroid"> + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java b/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java index e04676a..767c31f 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java @@ -59,88 +59,11 @@ public Observable updateTodo(int id, Todo todo) { @Override public Observable> getTodos() { return mDbHelper.getTodos(); -// return Observable.create(new ObservableOnSubscribe>() { -// @Override -// public void subscribe(final ObservableEmitter> emitter) throws Exception { -// mApiHelper.getTodos() -// .subscribeOn(Schedulers.io()) -// .observeOn(AndroidSchedulers.mainThread()) -// .subscribeWith(new Observer>() { -// @Override -// public void onSubscribe(Disposable d) { -// -// } -// -// @Override -// public void onNext(final ArrayList todos) { -// Log.i(AppDataManager.class.getSimpleName(), "Next"); -// mDbHelper.deleteTodos() -// .subscribeOn(Schedulers.io()) -// .observeOn(AndroidSchedulers.mainThread()) -// .subscribe(new Observer() { -// @Override -// public void onSubscribe(Disposable d) { -// -// } -// -// @Override -// public void onNext(Boolean aBoolean) { -// for (Todo todo : todos) { -// Log.i(AppDataManager.class.getSimpleName(), todo.getTitle()); -// mDbHelper.saveTodo(todo); -// } -// emitter.onNext(todos); -// } -// -// @Override -// public void onError(Throwable e) { -// emitter.onError(e); -// } -// -// @Override -// public void onComplete() { -// -// } -// }); -// } -// -// @Override -// public void onError(Throwable e) { -// Log.i(AppDataManager.class.getSimpleName(), "Errrr"); -// mDbHelper.getTodos() -// .subscribeOn(Schedulers.io()) -// .observeOn(AndroidSchedulers.mainThread()) -// .subscribe(new Observer>() { -// @Override -// public void onSubscribe(Disposable d) { -// -// } -// -// @Override -// public void onNext(ArrayList todos) { -// Log.i(AppDataManager.class.getSimpleName(), "Size of the array is" + todos.size()); -// emitter.onNext(todos); -// } -// -// @Override -// public void onError(Throwable e) { -// emitter.onError(e); -// } -// -// @Override -// public void onComplete() { -// -// } -// }); -// } -// -// @Override -// public void onComplete() { -// -// } -// }); -// } -// }); } + + @Override + public Observable> getDbTodos() { + return mDbHelper.getTodos(); + } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java b/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java index c517318..fb15402 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java @@ -2,12 +2,19 @@ import com.blink22.android.mvpandroid.data.api.ApiHelper; import com.blink22.android.mvpandroid.data.db.DbHelper; +import com.blink22.android.mvpandroid.data.db.model.Todo; import com.blink22.android.mvpandroid.data.prefs.PrefsHelper; +import java.util.ArrayList; + +import io.reactivex.Observable; + /** * Created by ahmedghazy on 7/30/18. */ public interface DataManager extends PrefsHelper, ApiHelper{ + Observable> getDbTodos(); + } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountAuthenticator.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountAuthenticator.java new file mode 100644 index 0000000..6dac63d --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountAuthenticator.java @@ -0,0 +1,56 @@ +package com.blink22.android.mvpandroid.data.db; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +import android.accounts.AbstractAccountAuthenticator; +import android.accounts.Account; +import android.accounts.AccountAuthenticatorResponse; +import android.accounts.NetworkErrorException; +import android.content.Context; +import android.os.Bundle; + +/** + * This is stubbed because we don't need any authentication to access the pretend RSS feed. + */ +public class AccountAuthenticator extends AbstractAccountAuthenticator { + public AccountAuthenticator(Context c) { + super(c); + } + + @Override + public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { + return null; + } + + @Override + public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { + return null; + } + + @Override + public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { + return null; + } + + @Override + public String getAuthTokenLabel(String authTokenType) { + return null; + } + + @Override + public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { + return null; + } + + @Override + public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { + return null; + } + + @Override + public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { + return null; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountGeneral.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountGeneral.java new file mode 100644 index 0000000..4db0eb9 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountGeneral.java @@ -0,0 +1,69 @@ +package com.blink22.android.mvpandroid.data.db; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.ContentResolver; +import android.content.Context; +import android.os.Bundle; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +public final class AccountGeneral { + /** + * This is the type of account we are using. i.e. we can specify our app or apps + * to have different types, such as 'read-only', 'sync-only', & 'admin'. + */ + private static final String ACCOUNT_TYPE = "com.blink22.android.mvpandroid"; + + /** + * This is the name that appears in the Android 'Accounts' settings. + */ + private static final String ACCOUNT_NAME = "Example Sync"; + + + /** + * Gets the standard sync account for our app. + * @return {@link Account} + */ + public static Account getAccount() { + return new Account(ACCOUNT_NAME, ACCOUNT_TYPE); + } + + /** + * Creates the standard sync account for our app. + * @param c {@link Context} + */ + public static void createSyncAccount(Context c) { + // Flag to determine if this is a new account or not + boolean created = false; + + // Get an account and the account manager + Account account = getAccount(); + AccountManager manager = (AccountManager)c.getSystemService(Context.ACCOUNT_SERVICE); + + // Attempt to explicitly create the account with no password or extra data + if (manager.addAccountExplicitly(account, null, null)) { + final String AUTHORITY = DatabaseContract.CONTENT_AUTHORITY; + final long SYNC_FREQUENCY = 60 * 60; // 1 hour (seconds) + + // Inform the system that this account supports sync + ContentResolver.setIsSyncable(account, AUTHORITY, 1); + + // Inform the system that this account is eligible for auto sync when the network is up + ContentResolver.setSyncAutomatically(account, AUTHORITY, true); + + // Recommend a schedule for automatic synchronization. The system may modify this based + // on other scheduled syncs and network utilization. + ContentResolver.addPeriodicSync(account, AUTHORITY, new Bundle(), SYNC_FREQUENCY); + + created = true; + } + + // Force a sync if the account was just created + if (created) { + SyncAdapter.performSync(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AuthenticatorService.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AuthenticatorService.java new file mode 100644 index 0000000..61c08e5 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AuthenticatorService.java @@ -0,0 +1,31 @@ +package com.blink22.android.mvpandroid.data.db; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.support.annotation.Nullable; + +/** + * This is used only by Android to run our {@link AccountAuthenticator}. + */ +public class AuthenticatorService extends Service { + private AccountAuthenticator authenticator; + + + @Override + public void onCreate() { + // Instantiate our authenticator when the service is created + this.authenticator = new AccountAuthenticator(this); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + // Return the authenticator's IBinder + return authenticator.getIBinder(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/CleanupJobService.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/CleanupJobService.java new file mode 100644 index 0000000..88bb2f9 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/CleanupJobService.java @@ -0,0 +1,47 @@ +package com.blink22.android.mvpandroid.data.db; + +import android.app.job.JobParameters; +import android.app.job.JobService; +import android.os.AsyncTask; +import android.util.Log; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +public class CleanupJobService extends JobService { + private static final String TAG = CleanupJobService.class.getSimpleName(); + + @Override + public boolean onStartJob(JobParameters params) { + Log.d(TAG, "Cleanup job started"); + new CleanupTask().execute(params); + + return true; + } + + @Override + public boolean onStopJob(JobParameters params) { + return false; + } + + /* Handle access to the database on a background thread */ + private class CleanupTask extends AsyncTask { + + @Override + protected JobParameters doInBackground(JobParameters... params) { + String where = String.format("%s", DatabaseContract.TodoColumns.DONE); + String[] args = {"true"}; + + int count = getContentResolver().delete(DatabaseContract.CONTENT_URI, where, args); + Log.d(TAG, "Cleaned up " + count + " completed tasks"); + + return params[0]; + } + + @Override + protected void onPostExecute(JobParameters jobParameters) { + jobFinished(jobParameters, false); + } + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/DatabaseContract.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/DatabaseContract.java new file mode 100644 index 0000000..824d342 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/DatabaseContract.java @@ -0,0 +1,56 @@ +package com.blink22.android.mvpandroid.data.db; + +import android.database.Cursor; +import android.net.Uri; +import android.provider.BaseColumns; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +public class DatabaseContract { + //Database schema information + public static final String TABLE_TODOS = "todos"; + + public static final class TodoColumns implements BaseColumns { + //Task ID + public static final String ID = "id"; + //Task description + public static final String DESCRIPTION = "description"; + //Completed marker + public static final String TITLE = "title"; + //Priority marker + public static final String DONE = "done"; + } + + //Unique authority string for the content provider + public static final String CONTENT_AUTHORITY = "com.blink22.android.mvpandroid"; + + /* Sort order constants */ + //Priority first, Completed last, the rest by date + public static final String DEFAULT_SORT = String.format("%s ASC", + TodoColumns.TITLE); + + //Base content Uri for accessing the provider + public static final Uri CONTENT_URI = new Uri.Builder().scheme("content") + .authority(CONTENT_AUTHORITY) + .appendPath(TABLE_TODOS) + .build(); + + public static Uri getElementUri(int id) { + return new Uri.Builder().scheme("content") + .authority(CONTENT_AUTHORITY) + .appendPath(TABLE_TODOS) + .appendPath(Integer.toString(id)) + .build(); + } + + /* Helpers to retrieve column values */ + public static String getColumnString(Cursor cursor, String columnName) { + return cursor.getString( cursor.getColumnIndex(columnName) ); + } + + public static int getColumnInt(Cursor cursor, String columnName) { + return cursor.getInt( cursor.getColumnIndex(columnName) ); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncAdapter.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncAdapter.java new file mode 100644 index 0000000..c611df6 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncAdapter.java @@ -0,0 +1,261 @@ +package com.blink22.android.mvpandroid.data.db; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +import android.accounts.Account; +import android.content.AbstractThreadedSyncAdapter; +import android.content.ContentProviderClient; +import android.content.ContentProviderOperation; +import android.content.ContentResolver; +import android.content.Context; +import android.content.OperationApplicationException; +import android.content.SyncResult; +import android.database.Cursor; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; + +import com.blink22.android.mvpandroid.BaseApp; +import com.blink22.android.mvpandroid.data.DataManager; +import com.blink22.android.mvpandroid.data.db.model.Todo; +import com.blink22.android.mvpandroid.di.PerSyncService; +import com.blink22.android.mvpandroid.di.component.DaggerSyncAdapterComponent; +import com.blink22.android.mvpandroid.di.component.SyncAdapterComponent; +import com.blink22.android.mvpandroid.di.module.SyncAdapterModule; +import com.blink22.android.mvpandroid.ui.todos.TodosContract; + +import org.json.JSONArray; +import org.json.JSONException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +/** + * This is used by the Android framework to perform synchronization. IMPORTANT: do NOT create + * new Threads to perform logic, Android will do this for you; hence, the name. + * + * The goal here to perform synchronization, is to do it efficiently as possible. We use some + * ContentProvider features to batch our writes to the local data source. Be sure to handle all + * possible exceptions accordingly; random crashes is not a good user-experience. + */ + +@PerSyncService +public class SyncAdapter extends AbstractThreadedSyncAdapter { + @Inject + public DataManager mDataManager; + + private static final String TAG = "SYNC_ADAPTER"; + + /** + * This gives us access to our local data source. + */ + private final ContentResolver resolver; + + + public SyncAdapter(Context c, boolean autoInit) { + this(c, autoInit, false); + } + + public SyncAdapter(Context c, boolean autoInit, boolean parallelSync) { + super(c, autoInit, parallelSync); + this.resolver = c.getContentResolver(); + + SyncAdapterComponent component = DaggerSyncAdapterComponent.builder() + .applicationComponent(((BaseApp)c.getApplicationContext()).getComponent()) + .syncAdapterModule(new SyncAdapterModule(this)) + .build(); + + component.inject(this); + } + + /** + * This method is run by the Android framework, on a new Thread, to perform a sync. + * @param account Current account + * @param extras Bundle extras + * @param authority Content authority + * @param provider {@link ContentProviderClient} + * @param syncResult Object to write stats to + */ + @Override + public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { + Log.w(TAG, "Starting synchronization..."); + + try { + // Synchronize our news feed + syncNewsFeed(syncResult); + + // Add any other things you may want to sync + + } catch (IOException ex) { + Log.e(TAG, "Error synchronizing!", ex); + syncResult.stats.numIoExceptions++; + } catch (JSONException ex) { + Log.e(TAG, "Error synchronizing!", ex); + syncResult.stats.numParseExceptions++; + } catch (RemoteException |OperationApplicationException ex) { + Log.e(TAG, "Error synchronizing!", ex); + syncResult.stats.numAuthExceptions++; + } + + Log.w(TAG, "Finished synchronization!"); + } + + /** + * Performs synchronization of our pretend news feed source. + * @param syncResult Write our stats to this + */ + private void syncNewsFeed(final SyncResult syncResult) throws IOException, JSONException, RemoteException, OperationApplicationException { + final String rssFeedEndpoint = "http://www.examplejsonnews.com"; + + // We need to collect all the network items in a hash table + Log.i(TAG, "Fetching server entries..."); + + + mDataManager.getTodos() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(ArrayList todos) { + try { + onDataFeched(todos, syncResult); + } + catch (Exception e) { + + } + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + + } + }); + + } + + void onDataFeched(ArrayList todosList, SyncResult syncResult) throws OperationApplicationException, RemoteException{ + + Map todos = new HashMap<>(); + + for (Todo todo: todosList) { + todos.put( todo.getId(), todo); + } + + // Create list for batching ContentProvider transactions + ArrayList batch = new ArrayList<>(); + + // Compare the hash table of network entries to all the local entries + Log.i(TAG, "Fetching local entries..."); + Cursor c = resolver.query(DatabaseContract.CONTENT_URI, null, null, null, null, null); + + + + assert c != null; + c.moveToFirst(); + + int id; + String title; + String description; + boolean done; + Todo found; + Log.i(getClass().getSimpleName(), "found" + c.getCount()); + Log.i(getClass().getSimpleName(), "found" + c.getCount()); + Log.i(getClass().getSimpleName(), "found" + c.getCount()); + for (int i = 0; i < c.getCount(); i++) { + Log.i(getClass().getSimpleName(), "hereeeeeeeee" + i); + + syncResult.stats.numEntries++; + + Log.i(getClass().getSimpleName(), "numEnt" + i); + + // Create local article entry + id = c.getInt(c.getColumnIndex(DatabaseContract.TodoColumns.ID)); + title = c.getString(c.getColumnIndex(DatabaseContract.TodoColumns.TITLE)); + description = c.getString(c.getColumnIndex(DatabaseContract.TodoColumns.DESCRIPTION)); + done = c.getInt(c.getColumnIndex(DatabaseContract.TodoColumns.DONE)) != 0; + + // Try to retrieve the local entry from network entries + found = todos.get(id); + if (found != null) { + Log.i(getClass().getSimpleName(), "found"); + // The entry exists, remove from hash table to prevent re-inserting it + todos.remove(id); + + // Check to see if it needs to be updated + if ( + !title.equals(found.getTitle()) || + !description.equals(found.getDescription()) || + done != found.isDone()) { + // Batch an update for the existing record + Log.i(TAG, "Scheduling update: " + title); + batch.add(ContentProviderOperation.newUpdate(DatabaseContract.getElementUri(id)) + .withSelection(DatabaseContract.TodoColumns.ID + "='" + id + "'", new String[]{Integer.toString(id)}) + .withValue(DatabaseContract.TodoColumns.TITLE, found.getTitle()) + .withValue(DatabaseContract.TodoColumns.DESCRIPTION, found.getDescription()) + .withValue(DatabaseContract.TodoColumns.DONE, found.isDone()) + .build()); + syncResult.stats.numUpdates++; + } + } else { + // Entry doesn't exist, remove it from the local database + Log.i(TAG, "Scheduling delete: " + title); + batch.add(ContentProviderOperation.newDelete(DatabaseContract.getElementUri(id)) + .withSelection(DatabaseContract.TodoColumns.ID + "='" + id + "'", new String[]{Integer.toString(id)}) + .build()); + syncResult.stats.numDeletes++; + } + c.moveToNext(); + } + c.close(); + + // Add all the new entries + for (Todo todo : todos.values()) { + Log.i(TAG, "Scheduling insert: " + todo.getTitle()); + batch.add(ContentProviderOperation.newInsert(DatabaseContract.CONTENT_URI) + .withValue(DatabaseContract.TodoColumns.TITLE, todo.getTitle()) + .withValue(DatabaseContract.TodoColumns.DESCRIPTION, todo.getDescription()) + .withValue(DatabaseContract.TodoColumns.DONE, todo.isDone()) + .build()); + syncResult.stats.numInserts++; + } + + // Synchronize by performing batch update + Log.i(TAG, "Merge solution ready, applying batch update..."); + resolver.applyBatch(DatabaseContract.CONTENT_AUTHORITY, batch); + resolver.notifyChange(DatabaseContract.CONTENT_URI, // URI where data was modified + null, // No local observer + false); // IMPORTANT: Do not sync to network + } + + /** + * Manual force Android to perform a sync with our SyncAdapter. + */ + public static void performSync() { + Bundle b = new Bundle(); + b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); + ContentResolver.requestSync(AccountGeneral.getAccount(), + DatabaseContract.CONTENT_AUTHORITY, b); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncService.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncService.java new file mode 100644 index 0000000..97f219f --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncService.java @@ -0,0 +1,38 @@ +package com.blink22.android.mvpandroid.data.db; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.support.annotation.Nullable; + +/** + * This is used only by Android to run our {@link SyncAdapter}. + */ +public class SyncService extends Service { + /** + * Lock use to synchronize instantiation of SyncAdapter. + */ + private static final Object LOCK = new Object(); + private static SyncAdapter syncAdapter; + + + @Override + public void onCreate() { + // SyncAdapter is not Thread-safe + synchronized (LOCK) { + // Instantiate our SyncAdapter + syncAdapter = new SyncAdapter(this, false); + } + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + // Return our SyncAdapter's IBinder + return syncAdapter.getSyncAdapterBinder(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/TodoProvider.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/TodoProvider.java new file mode 100644 index 0000000..d5919d4 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/TodoProvider.java @@ -0,0 +1,280 @@ +package com.blink22.android.mvpandroid.data.db; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +import android.app.job.JobInfo; +import android.app.job.JobScheduler; +import android.content.ComponentName; +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.support.annotation.Nullable; +import android.text.format.DateUtils; +import android.util.Log; + +import io.realm.DynamicRealm; +import io.realm.Realm; +import io.realm.RealmConfiguration; +import io.realm.RealmMigration; +import io.realm.RealmResults; +import io.realm.RealmSchema; + +import com.blink22.android.mvpandroid.data.db.DatabaseContract.TodoColumns; +import com.blink22.android.mvpandroid.data.db.model.Todo; + + +public class TodoProvider extends ContentProvider { + private static final String TAG = TodoProvider.class.getSimpleName(); + + private static final int CLEANUP_JOB_ID = 43; + private static final int TODOS = 100; + private static final int TODO_WITH_ID = 101; + + private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + static { + // content://com.example.rgher.realmtodo/tasks + sUriMatcher.addURI(DatabaseContract.CONTENT_AUTHORITY, + DatabaseContract.TABLE_TODOS, + TODOS); + + // content://com.example.rgher.realmtodo/tasks/id + sUriMatcher.addURI(DatabaseContract.CONTENT_AUTHORITY, + DatabaseContract.TABLE_TODOS + "/#", + TODO_WITH_ID); + } + + + @Override + public boolean onCreate() { + + //Innitializing RealmDB + Realm.init(getContext()); + RealmConfiguration config = new RealmConfiguration.Builder() + .schemaVersion(1) + .migration(new MyRealmMigration()) + .build(); + + Realm.setDefaultConfiguration(config); + +// manageCleanupJob(); + + return true; + } + + @Nullable + @Override + public String getType(Uri uri) { + return null; /* Not used */ + } + + @Nullable + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + + int match = sUriMatcher.match(uri); + + //Get Realm Instance + Realm realm = Realm.getDefaultInstance(); + MatrixCursor myCursor = new MatrixCursor( new String[]{ + TodoColumns.ID, + TodoColumns.TITLE, + TodoColumns.DESCRIPTION, + TodoColumns.DONE + }); + + try { + switch (match) { + //Expected "query all" Uri: content://com.example.rgher.realmtodo/tasks + + case TODOS: + RealmResults todoRealmResults = realm.where(Todo.class).findAll(); + for (Todo todo : todoRealmResults) { + Log.i(getClass().getSimpleName(), "tdo: " + todo.getTitle()); + Object[] rowData = new Object[]{todo.getId(), todo.getTitle(), todo.getDescription(), todo.isDone() ? 1 : 0}; + + Log.i(getClass().getSimpleName(), "^^^" + todo.isDone()); + + myCursor.addRow(rowData); + Log.v("RealmDB", todo.toString()); + } + break; + + //Expected "query one" Uri: content://com.example.rgher.realmtodo/tasks/{id} + case TODO_WITH_ID: + Integer id = Integer.parseInt(uri.getPathSegments().get(1)); + + Todo todo = realm.where(Todo.class).equalTo(TodoColumns.ID, id).findFirst(); + myCursor.addRow(new Object[]{todo.getId(), todo.getTitle(), todo.getDescription(), todo.isDone()}); + Log.v("RealmDB", todo.toString()); + break; + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); + } + + + myCursor.setNotificationUri(getContext().getContentResolver(), uri); + } finally { + realm.close(); + } + + + + return myCursor; + + } + + @Nullable + @Override + public Uri insert(Uri uri, final ContentValues contentValues) { + //COMPLETE: Expected Uri: content://com.example.rgher.realmtodo/tasks + + //final SQLiteDatabase taskDb = mDbHelper.getReadableDatabase(); + int match = sUriMatcher.match(uri); + Uri returnUri; + + //Get Realm Instance + Realm realm = Realm.getDefaultInstance(); + try { + switch (match) { + case TODOS: + realm.executeTransaction(new Realm.Transaction() { + @Override + public void execute(Realm realm) { + + Number currId = realm.where(Todo.class).max(TodoColumns.ID); + + Integer nextId = (currId == null) ? 1 : currId.intValue() + 1; + + Todo todo = realm.createObject(Todo.class, nextId); + todo.setTitle(contentValues.getAsString(TodoColumns.TITLE)); + todo.setDescription(contentValues.getAsString(TodoColumns.DESCRIPTION)); + todo.setDone(contentValues.getAsBoolean(TodoColumns.DONE)); + } + }); + returnUri = ContentUris.withAppendedId(DatabaseContract.CONTENT_URI, '1'); + break; + + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); + } + + getContext().getContentResolver().notifyChange(uri, null); + }finally { + realm.close(); + } + return returnUri; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + + //Expected Uri: content://com.example.rgher.realmtodo/tasks/{id} + Realm realm = Realm.getDefaultInstance(); + + int match = sUriMatcher.match(uri); + int nrUpdated = 0; + try { + switch (match) { + case TODO_WITH_ID: + Integer id = Integer.parseInt(uri.getPathSegments().get(1)); + + Todo todo = realm.where(Todo.class).equalTo(TodoColumns.ID, id).findFirst(); + realm.beginTransaction(); + todo.setDone(values.getAsBoolean(TodoColumns.DONE)); + nrUpdated++; + realm.commitTransaction(); + break; + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); + } + + + } finally { + realm.close(); + } + + if (nrUpdated != 0) { + getContext().getContentResolver().notifyChange(uri, null); + } + return nrUpdated; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + int count = 0; + Realm realm = Realm.getDefaultInstance(); + try { + switch (sUriMatcher.match(uri)) { + case TODO_WITH_ID: + Integer id = Integer.parseInt(uri.getPathSegments().get(1)); + + Todo myTask = realm.where(Todo.class).equalTo(TodoColumns.ID, id).findFirst(); + realm.beginTransaction(); + if(myTask != null) { + myTask.deleteFromRealm(); + count++; + } + realm.commitTransaction(); + break; + default: + throw new IllegalArgumentException("Illegal delete URI"); + } + } finally { + realm.close(); + } + if (count > 0) { + //Notify observers of the change + getContext().getContentResolver().notifyChange(uri, null); + } + + return count; + } + +// /* Initiate a periodic job to clear out completed items */ +// private void manageCleanupJob() { +// Log.d(TAG, "Scheduling cleanup job"); +// JobScheduler jobScheduler = (JobScheduler) getContext() +// .getSystemService(Context.JOB_SCHEDULER_SERVICE); +// +// //Run the job approximately every hour +// long jobInterval = DateUtils.MINUTE_IN_MILLIS; +// +// ComponentName jobService = new ComponentName(getContext(), CleanupJobService.class); +// +// JobInfo task = new JobInfo.Builder(CLEANUP_JOB_ID, jobService) +// .setPeriodic(jobInterval) +// .setPersisted(true) +// .build(); +// +// if (jobScheduler.schedule(task) != JobScheduler.RESULT_SUCCESS) { +// Log.w(TAG, "Unable to schedule cleanup job"); +// } +// } +} + +// Example of REALM migration +class MyRealmMigration implements RealmMigration { + @Override + public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { + + RealmSchema schema = realm.getSchema(); + + if (oldVersion != 0) { + schema.create(DatabaseContract.TABLE_TODOS) + .addField(DatabaseContract.TodoColumns.ID, Integer.class) + .addField(TodoColumns.TITLE, String.class) + .addField(TodoColumns.DESCRIPTION, String.class) + .addField(TodoColumns.DONE, Boolean.class); + oldVersion++; + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java index 58a12af..7a4756b 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java @@ -17,6 +17,10 @@ public class Todo extends RealmObject { private String description; private boolean done; + public Todo(int id) { + this.id = id; + } + public void set(Todo todo) { setTitle(todo.getTitle()); setDescription(todo.getDescription()); diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/PerSyncService.java b/app/src/main/java/com/blink22/android/mvpandroid/di/PerSyncService.java new file mode 100644 index 0000000..05b6faa --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/PerSyncService.java @@ -0,0 +1,15 @@ +package com.blink22.android.mvpandroid.di; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Scope; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +@Scope +@Retention(RetentionPolicy.RUNTIME) +public @interface PerSyncService { +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/component/SyncAdapterComponent.java b/app/src/main/java/com/blink22/android/mvpandroid/di/component/SyncAdapterComponent.java new file mode 100644 index 0000000..d31aa1e --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/component/SyncAdapterComponent.java @@ -0,0 +1,19 @@ +package com.blink22.android.mvpandroid.di.component; + +import com.blink22.android.mvpandroid.data.db.SyncAdapter; +import com.blink22.android.mvpandroid.di.PerSyncService; +import com.blink22.android.mvpandroid.di.module.SyncAdapterModule; + +import javax.inject.Singleton; + +import dagger.Component; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +@PerSyncService +@Component(dependencies = ApplicationComponent.class, modules = SyncAdapterModule.class) +public interface SyncAdapterComponent { + void inject(SyncAdapter syncAdapter); +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/module/SyncAdapterModule.java b/app/src/main/java/com/blink22/android/mvpandroid/di/module/SyncAdapterModule.java new file mode 100644 index 0000000..3ed002c --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/module/SyncAdapterModule.java @@ -0,0 +1,24 @@ +package com.blink22.android.mvpandroid.di.module; + +import com.blink22.android.mvpandroid.data.db.SyncAdapter; + +import dagger.Module; +import dagger.Provides; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +@Module +public class SyncAdapterModule { + SyncAdapter mSyncAdapter; + + public SyncAdapterModule(SyncAdapter syncAdapter) { + mSyncAdapter = syncAdapter; + } + + @Provides + SyncAdapter provideSyncAdapter() { + return mSyncAdapter; + } +} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java index e1a6e91..18d9efc 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java @@ -1,7 +1,11 @@ package com.blink22.android.mvpandroid.ui.base; import android.content.Intent; +import android.database.ContentObserver; +import android.net.Uri; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.os.PersistableBundle; import android.support.annotation.Nullable; import android.support.design.widget.NavigationView; @@ -9,11 +13,15 @@ import android.support.v4.app.FragmentManager; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; import com.blink22.android.mvpandroid.BaseApp; import com.blink22.android.mvpandroid.R; +import com.blink22.android.mvpandroid.data.db.AccountGeneral; +import com.blink22.android.mvpandroid.data.db.DatabaseContract; +import com.blink22.android.mvpandroid.data.db.SyncAdapter; import com.blink22.android.mvpandroid.di.component.ActivityComponent; import com.blink22.android.mvpandroid.di.component.DaggerActivityComponent; import com.blink22.android.mvpandroid.di.module.ActivityModule; @@ -31,6 +39,8 @@ public abstract class BaseActivity extends AppCompatActivity implements Navigati @BindView(R.id.drawer_layout) DrawerLayout mDrawerLayout; @BindView(R.id.nav_view) NavigationView navigationView; + private TodosObserver mTodosObserver; + public ActivityComponent getActivityComponent() { return mActivityComponent; } @@ -67,6 +77,38 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { .add(R.id.fragment_container, fragment) .commit(); } + + // Create your sync account + AccountGeneral.createSyncAccount(this); + + // Perform a manual sync by calling this: + SyncAdapter.performSync(); + + + // Setup example content observer + mTodosObserver = new TodosObserver(); + } + + @Override + protected void onStart() { + super.onStart(); + + // Register the observer at the start of our activity + getContentResolver().registerContentObserver( + DatabaseContract.CONTENT_URI, // Uri to observe (our articles) + true, // Observe its descendants + mTodosObserver); // The observer + } + + @Override + protected void onStop() { + super.onStop(); + + + if (mTodosObserver != null) { + // Unregister the observer at the stop of our activity + getContentResolver().unregisterContentObserver(mTodosObserver); + } } public boolean onNavigationItemSelected(MenuItem menuItem) { @@ -82,4 +124,21 @@ public boolean onNavigationItemSelected(MenuItem menuItem) { return true; } + + private void refreshArticles() { + Log.i(getClass().getName(), "Articles data has changed!"); + } + + private final class TodosObserver extends ContentObserver { + private TodosObserver() { + // Ensure callbacks happen on the UI thread + super(new Handler(Looper.getMainLooper())); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + // Handle your data changes here!!! + refreshArticles(); + } + } } diff --git a/app/src/main/res/xml/authenticator.xml b/app/src/main/res/xml/authenticator.xml new file mode 100644 index 0000000..bba9560 --- /dev/null +++ b/app/src/main/res/xml/authenticator.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/app/src/main/res/xml/syncadapter.xml b/app/src/main/res/xml/syncadapter.xml new file mode 100644 index 0000000..532e85d --- /dev/null +++ b/app/src/main/res/xml/syncadapter.xml @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/app/src/main/res/xml/syncsettings.xml b/app/src/main/res/xml/syncsettings.xml new file mode 100644 index 0000000..ff894ac --- /dev/null +++ b/app/src/main/res/xml/syncsettings.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file From f8dbe5d8a2217eabf9a8b12899bc0870639bc9ad Mon Sep 17 00:00:00 2001 From: Ahmed Date: Thu, 2 Aug 2018 08:30:48 +0200 Subject: [PATCH 3/6] Add sync adapter --- app/src/main/AndroidManifest.xml | 11 +- .../apiinterfaces/TodosService.java | 28 -- .../mvpandroid/data/AppDataManager.java | 118 +++++++- .../android/mvpandroid/data/DataManager.java | 5 +- .../mvpandroid/data/api/AppApiHelper.java | 1 + .../mvpandroid/data/db/AccountGeneral.java | 69 ----- .../mvpandroid/data/db/AppDbHelper.java | 9 - .../mvpandroid/data/db/CleanupJobService.java | 47 --- .../mvpandroid/data/db/DatabaseContract.java | 56 ---- .../mvpandroid/data/db/SyncAdapter.java | 261 ---------------- .../mvpandroid/data/db/SyncService.java | 38 --- .../mvpandroid/data/db/TodoProvider.java | 280 ------------------ .../mvpandroid/data/db/model/Todo.java | 9 + .../model}/NavigationItemEnum.java | 2 +- .../mvpandroid/data/prefs/AppPrefsHelper.java | 11 +- .../mvpandroid/data/prefs/PrefsHelper.java | 4 +- .../android/mvpandroid/di/AppModule.java | 27 -- .../mvpandroid/di/NetworkComponent.java | 21 -- .../android/mvpandroid/di/NetworkModule.java | 91 ------ .../di/component/ActivityComponent.java | 4 +- .../di/component/ApplicationComponent.java | 7 +- .../di/component/SyncAdapterComponent.java | 8 +- .../mvpandroid/di/module/ActivityModule.java | 3 +- .../di/module/SyncAdapterModule.java | 9 +- .../di/{ => scope}/PerActivity.java | 2 +- .../di/{ => scope}/PerSyncService.java | 2 +- .../mvpandroid/network/NetworkManager.java | 53 ---- .../mvpandroid/network/TodosSubscriber.java | 105 ------- .../db => service}/AccountAuthenticator.java | 2 +- .../mvpandroid/service/AccountGeneral.java | 42 +++ .../db => service}/AuthenticatorService.java | 6 +- .../mvpandroid/service/SyncAdapter.java | 63 ++++ .../mvpandroid/service/SyncService.java | 33 +++ .../mvpandroid/service/TodoProvider.java | 65 ++++ .../mvpandroid/ui/base/BaseActivity.java | 99 ++----- .../mvpandroid/ui/base/BasePresenter.java | 36 ++- .../mvpandroid/ui/base/IBasePresenter.java | 2 +- .../ui/newtodo/NewTodoActivity.java | 12 +- .../ui/newtodo/NewTodoContract.java | 6 +- .../ui/newtodo/NewTodoFragment.java | 59 ++-- .../ui/newtodo/NewTodoPresenter.java | 68 ++--- .../mvpandroid/ui/todos/TodosActivity.java | 32 +- .../{adapters => ui/todos}/TodosAdapter.java | 11 +- .../mvpandroid/ui/todos/TodosContract.java | 2 +- .../mvpandroid/ui/todos/TodosFragment.java | 34 +-- .../mvpandroid/ui/todos/TodosPresenter.java | 82 +++-- .../{viewHolders => ui/todos}/TodosVH.java | 20 +- .../mvpandroid/utils/AppConstants.java | 2 + app/src/main/res/values/strings.xml | 6 +- db.json | 184 ++++++------ readme.md | 4 +- 51 files changed, 688 insertions(+), 1463 deletions(-) delete mode 100644 app/src/main/java/com/blink22/android/mvpandroid/apiinterfaces/TodosService.java delete mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountGeneral.java delete mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/CleanupJobService.java delete mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/DatabaseContract.java delete mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncAdapter.java delete mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncService.java delete mode 100644 app/src/main/java/com/blink22/android/mvpandroid/data/db/TodoProvider.java rename app/src/main/java/com/blink22/android/mvpandroid/{models => data/model}/NavigationItemEnum.java (95%) delete mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/AppModule.java delete mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/NetworkComponent.java delete mode 100644 app/src/main/java/com/blink22/android/mvpandroid/di/NetworkModule.java rename app/src/main/java/com/blink22/android/mvpandroid/di/{ => scope}/PerActivity.java (82%) rename app/src/main/java/com/blink22/android/mvpandroid/di/{ => scope}/PerSyncService.java (83%) delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/network/NetworkManager.java delete mode 100755 app/src/main/java/com/blink22/android/mvpandroid/network/TodosSubscriber.java rename app/src/main/java/com/blink22/android/mvpandroid/{data/db => service}/AccountAuthenticator.java (97%) create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/service/AccountGeneral.java rename app/src/main/java/com/blink22/android/mvpandroid/{data/db => service}/AuthenticatorService.java (78%) create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/service/SyncAdapter.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/service/SyncService.java create mode 100644 app/src/main/java/com/blink22/android/mvpandroid/service/TodoProvider.java rename app/src/main/java/com/blink22/android/mvpandroid/{adapters => ui/todos}/TodosAdapter.java (73%) rename app/src/main/java/com/blink22/android/mvpandroid/{viewHolders => ui/todos}/TodosVH.java (72%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 66c4509..851f721 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,10 +27,10 @@ - + @@ -39,7 +39,7 @@ - + @@ -48,8 +48,9 @@ android:resource="@xml/authenticator"/> - diff --git a/app/src/main/java/com/blink22/android/mvpandroid/apiinterfaces/TodosService.java b/app/src/main/java/com/blink22/android/mvpandroid/apiinterfaces/TodosService.java deleted file mode 100644 index 863fc1b..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/apiinterfaces/TodosService.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.blink22.android.mvpandroid.apiinterfaces; - -import com.blink22.android.mvpandroid.data.db.model.Todo; - -import java.util.ArrayList; - -import io.reactivex.Observable; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; - -/** - * Created by ahmedghazy on 7/25/18. - */ - -public interface TodosService { - - @GET("/todos") - Observable> getTodos(); - - @POST("/todos") - Observable createTodo(@Body Todo todo); - - @PUT("/todos/{id}") - Observable updateTodo(@Path("id") int id, @Body Todo todo); -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java b/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java index 767c31f..fc5c568 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java @@ -1,6 +1,6 @@ package com.blink22.android.mvpandroid.data; -import android.util.Log; +import android.content.SyncResult; import com.blink22.android.mvpandroid.data.api.ApiHelper; import com.blink22.android.mvpandroid.data.db.DbHelper; @@ -8,6 +8,7 @@ import com.blink22.android.mvpandroid.data.prefs.PrefsHelper; import java.util.ArrayList; +import java.util.Date; import javax.inject.Inject; @@ -18,6 +19,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import io.realm.Realm; /** * Created by ahmedghazy on 7/30/18. @@ -35,15 +37,6 @@ public AppDataManager(ApiHelper apiHelper, DbHelper dbHelper, PrefsHelper prefsH mPrefsHelper = prefsHelper; } - @Override - public String getUserName() { - return mPrefsHelper.getUserName(); - } - - @Override - public void setUserName(String userName) { - mPrefsHelper.setUserName(userName); - } @Override public Observable saveTodo(Todo todo) { @@ -63,7 +56,108 @@ public Observable> getTodos() { } @Override - public Observable> getDbTodos() { - return mDbHelper.getTodos(); + public void syncData() { + mApiHelper.getTodos() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(final ArrayList apiTodos) { + mDbHelper.getTodos() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(final ArrayList dbTodos) { + for(Todo dbTodo: dbTodos) { + + boolean mostRecent = false; + boolean found = false; + for(Todo apiTodo: apiTodos) { + if(dbTodo.getId() == apiTodo.getId()) { + found = true; + if (new Date(dbTodo.getUpdatedDate()).compareTo(new Date(apiTodo.getUpdatedDate())) > 0) { + mostRecent = true; + } + } + } + + if(!found) { + mApiHelper.saveTodo(dbTodo).subscribeOn(Schedulers.io()).subscribe(); + + } + else { + if(mostRecent) { + mApiHelper.updateTodo(dbTodo.getId(), dbTodo).subscribeOn(Schedulers.io()).subscribe(); + } + } + } + + for(Todo apiTodo: apiTodos) { + boolean mostRecent = false; + boolean found = false; + for(Todo dbTodo: dbTodos) { + if(dbTodo.getId() == apiTodo.getId()) { + found = true; + if (new Date(apiTodo.getUpdatedDate()).compareTo(new Date(dbTodo.getUpdatedDate())) > 0) { + mostRecent = true; + } + } + } + + if(!found) { + mDbHelper.saveTodo(apiTodo).subscribeOn(Schedulers.io()).subscribe(); + } + else { + if(mostRecent) { + mDbHelper.updateTodo(apiTodo.getId(), apiTodo).subscribeOn(Schedulers.io()).subscribe(); + } + } + } + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + + } + }); + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + + } + }); + + } + + @Override + public boolean isSyncDone() { + return mPrefsHelper.isSyncDone(); + } + + @Override + public void setSyncDone(boolean syncRequired) { + mPrefsHelper.setSyncDone(syncRequired); } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java b/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java index fb15402..ed76ec3 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/DataManager.java @@ -1,5 +1,7 @@ package com.blink22.android.mvpandroid.data; +import android.content.SyncResult; + import com.blink22.android.mvpandroid.data.api.ApiHelper; import com.blink22.android.mvpandroid.data.db.DbHelper; import com.blink22.android.mvpandroid.data.db.model.Todo; @@ -8,6 +10,7 @@ import java.util.ArrayList; import io.reactivex.Observable; +import io.realm.Realm; /** * Created by ahmedghazy on 7/30/18. @@ -15,6 +18,6 @@ public interface DataManager extends PrefsHelper, ApiHelper{ - Observable> getDbTodos(); + void syncData(); } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/api/AppApiHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/api/AppApiHelper.java index 09cd486..8c87b9c 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/api/AppApiHelper.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/api/AppApiHelper.java @@ -3,6 +3,7 @@ import com.blink22.android.mvpandroid.data.db.model.Todo; import java.util.ArrayList; +import java.util.Date; import javax.inject.Inject; diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountGeneral.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountGeneral.java deleted file mode 100644 index 4db0eb9..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountGeneral.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.blink22.android.mvpandroid.data.db; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.ContentResolver; -import android.content.Context; -import android.os.Bundle; - -/** - * Created by ahmedghazy on 7/31/18. - */ - -public final class AccountGeneral { - /** - * This is the type of account we are using. i.e. we can specify our app or apps - * to have different types, such as 'read-only', 'sync-only', & 'admin'. - */ - private static final String ACCOUNT_TYPE = "com.blink22.android.mvpandroid"; - - /** - * This is the name that appears in the Android 'Accounts' settings. - */ - private static final String ACCOUNT_NAME = "Example Sync"; - - - /** - * Gets the standard sync account for our app. - * @return {@link Account} - */ - public static Account getAccount() { - return new Account(ACCOUNT_NAME, ACCOUNT_TYPE); - } - - /** - * Creates the standard sync account for our app. - * @param c {@link Context} - */ - public static void createSyncAccount(Context c) { - // Flag to determine if this is a new account or not - boolean created = false; - - // Get an account and the account manager - Account account = getAccount(); - AccountManager manager = (AccountManager)c.getSystemService(Context.ACCOUNT_SERVICE); - - // Attempt to explicitly create the account with no password or extra data - if (manager.addAccountExplicitly(account, null, null)) { - final String AUTHORITY = DatabaseContract.CONTENT_AUTHORITY; - final long SYNC_FREQUENCY = 60 * 60; // 1 hour (seconds) - - // Inform the system that this account supports sync - ContentResolver.setIsSyncable(account, AUTHORITY, 1); - - // Inform the system that this account is eligible for auto sync when the network is up - ContentResolver.setSyncAutomatically(account, AUTHORITY, true); - - // Recommend a schedule for automatic synchronization. The system may modify this based - // on other scheduled syncs and network utilization. - ContentResolver.addPeriodicSync(account, AUTHORITY, new Bundle(), SYNC_FREQUENCY); - - created = true; - } - - // Force a sync if the account was just created - if (created) { - SyncAdapter.performSync(); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java index cad40f4..f58f52f 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java @@ -3,7 +3,6 @@ import android.arch.lifecycle.Lifecycle; import android.arch.lifecycle.LifecycleObserver; import android.arch.lifecycle.OnLifecycleEvent; -import android.util.Log; import com.blink22.android.mvpandroid.data.db.model.Todo; @@ -29,14 +28,6 @@ public AppDbHelper(Realm realm) { mRealm = realm; } - @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) void start() { - - } - - @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) void stop() { - mRealm.close(); - } - @Override public Observable saveTodo(final Todo todo) { diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/CleanupJobService.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/CleanupJobService.java deleted file mode 100644 index 88bb2f9..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/CleanupJobService.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.blink22.android.mvpandroid.data.db; - -import android.app.job.JobParameters; -import android.app.job.JobService; -import android.os.AsyncTask; -import android.util.Log; - -/** - * Created by ahmedghazy on 7/31/18. - */ - -public class CleanupJobService extends JobService { - private static final String TAG = CleanupJobService.class.getSimpleName(); - - @Override - public boolean onStartJob(JobParameters params) { - Log.d(TAG, "Cleanup job started"); - new CleanupTask().execute(params); - - return true; - } - - @Override - public boolean onStopJob(JobParameters params) { - return false; - } - - /* Handle access to the database on a background thread */ - private class CleanupTask extends AsyncTask { - - @Override - protected JobParameters doInBackground(JobParameters... params) { - String where = String.format("%s", DatabaseContract.TodoColumns.DONE); - String[] args = {"true"}; - - int count = getContentResolver().delete(DatabaseContract.CONTENT_URI, where, args); - Log.d(TAG, "Cleaned up " + count + " completed tasks"); - - return params[0]; - } - - @Override - protected void onPostExecute(JobParameters jobParameters) { - jobFinished(jobParameters, false); - } - } -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/DatabaseContract.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/DatabaseContract.java deleted file mode 100644 index 824d342..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/DatabaseContract.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.blink22.android.mvpandroid.data.db; - -import android.database.Cursor; -import android.net.Uri; -import android.provider.BaseColumns; - -/** - * Created by ahmedghazy on 7/31/18. - */ - -public class DatabaseContract { - //Database schema information - public static final String TABLE_TODOS = "todos"; - - public static final class TodoColumns implements BaseColumns { - //Task ID - public static final String ID = "id"; - //Task description - public static final String DESCRIPTION = "description"; - //Completed marker - public static final String TITLE = "title"; - //Priority marker - public static final String DONE = "done"; - } - - //Unique authority string for the content provider - public static final String CONTENT_AUTHORITY = "com.blink22.android.mvpandroid"; - - /* Sort order constants */ - //Priority first, Completed last, the rest by date - public static final String DEFAULT_SORT = String.format("%s ASC", - TodoColumns.TITLE); - - //Base content Uri for accessing the provider - public static final Uri CONTENT_URI = new Uri.Builder().scheme("content") - .authority(CONTENT_AUTHORITY) - .appendPath(TABLE_TODOS) - .build(); - - public static Uri getElementUri(int id) { - return new Uri.Builder().scheme("content") - .authority(CONTENT_AUTHORITY) - .appendPath(TABLE_TODOS) - .appendPath(Integer.toString(id)) - .build(); - } - - /* Helpers to retrieve column values */ - public static String getColumnString(Cursor cursor, String columnName) { - return cursor.getString( cursor.getColumnIndex(columnName) ); - } - - public static int getColumnInt(Cursor cursor, String columnName) { - return cursor.getInt( cursor.getColumnIndex(columnName) ); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncAdapter.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncAdapter.java deleted file mode 100644 index c611df6..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncAdapter.java +++ /dev/null @@ -1,261 +0,0 @@ -package com.blink22.android.mvpandroid.data.db; - -/** - * Created by ahmedghazy on 7/31/18. - */ - -import android.accounts.Account; -import android.content.AbstractThreadedSyncAdapter; -import android.content.ContentProviderClient; -import android.content.ContentProviderOperation; -import android.content.ContentResolver; -import android.content.Context; -import android.content.OperationApplicationException; -import android.content.SyncResult; -import android.database.Cursor; -import android.os.Bundle; -import android.os.RemoteException; -import android.util.Log; - -import com.blink22.android.mvpandroid.BaseApp; -import com.blink22.android.mvpandroid.data.DataManager; -import com.blink22.android.mvpandroid.data.db.model.Todo; -import com.blink22.android.mvpandroid.di.PerSyncService; -import com.blink22.android.mvpandroid.di.component.DaggerSyncAdapterComponent; -import com.blink22.android.mvpandroid.di.component.SyncAdapterComponent; -import com.blink22.android.mvpandroid.di.module.SyncAdapterModule; -import com.blink22.android.mvpandroid.ui.todos.TodosContract; - -import org.json.JSONArray; -import org.json.JSONException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import javax.inject.Inject; - -import io.reactivex.Observer; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; - -/** - * This is used by the Android framework to perform synchronization. IMPORTANT: do NOT create - * new Threads to perform logic, Android will do this for you; hence, the name. - * - * The goal here to perform synchronization, is to do it efficiently as possible. We use some - * ContentProvider features to batch our writes to the local data source. Be sure to handle all - * possible exceptions accordingly; random crashes is not a good user-experience. - */ - -@PerSyncService -public class SyncAdapter extends AbstractThreadedSyncAdapter { - @Inject - public DataManager mDataManager; - - private static final String TAG = "SYNC_ADAPTER"; - - /** - * This gives us access to our local data source. - */ - private final ContentResolver resolver; - - - public SyncAdapter(Context c, boolean autoInit) { - this(c, autoInit, false); - } - - public SyncAdapter(Context c, boolean autoInit, boolean parallelSync) { - super(c, autoInit, parallelSync); - this.resolver = c.getContentResolver(); - - SyncAdapterComponent component = DaggerSyncAdapterComponent.builder() - .applicationComponent(((BaseApp)c.getApplicationContext()).getComponent()) - .syncAdapterModule(new SyncAdapterModule(this)) - .build(); - - component.inject(this); - } - - /** - * This method is run by the Android framework, on a new Thread, to perform a sync. - * @param account Current account - * @param extras Bundle extras - * @param authority Content authority - * @param provider {@link ContentProviderClient} - * @param syncResult Object to write stats to - */ - @Override - public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { - Log.w(TAG, "Starting synchronization..."); - - try { - // Synchronize our news feed - syncNewsFeed(syncResult); - - // Add any other things you may want to sync - - } catch (IOException ex) { - Log.e(TAG, "Error synchronizing!", ex); - syncResult.stats.numIoExceptions++; - } catch (JSONException ex) { - Log.e(TAG, "Error synchronizing!", ex); - syncResult.stats.numParseExceptions++; - } catch (RemoteException |OperationApplicationException ex) { - Log.e(TAG, "Error synchronizing!", ex); - syncResult.stats.numAuthExceptions++; - } - - Log.w(TAG, "Finished synchronization!"); - } - - /** - * Performs synchronization of our pretend news feed source. - * @param syncResult Write our stats to this - */ - private void syncNewsFeed(final SyncResult syncResult) throws IOException, JSONException, RemoteException, OperationApplicationException { - final String rssFeedEndpoint = "http://www.examplejsonnews.com"; - - // We need to collect all the network items in a hash table - Log.i(TAG, "Fetching server entries..."); - - - mDataManager.getTodos() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer>() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(ArrayList todos) { - try { - onDataFeched(todos, syncResult); - } - catch (Exception e) { - - } - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - }); - - } - - void onDataFeched(ArrayList todosList, SyncResult syncResult) throws OperationApplicationException, RemoteException{ - - Map todos = new HashMap<>(); - - for (Todo todo: todosList) { - todos.put( todo.getId(), todo); - } - - // Create list for batching ContentProvider transactions - ArrayList batch = new ArrayList<>(); - - // Compare the hash table of network entries to all the local entries - Log.i(TAG, "Fetching local entries..."); - Cursor c = resolver.query(DatabaseContract.CONTENT_URI, null, null, null, null, null); - - - - assert c != null; - c.moveToFirst(); - - int id; - String title; - String description; - boolean done; - Todo found; - Log.i(getClass().getSimpleName(), "found" + c.getCount()); - Log.i(getClass().getSimpleName(), "found" + c.getCount()); - Log.i(getClass().getSimpleName(), "found" + c.getCount()); - for (int i = 0; i < c.getCount(); i++) { - Log.i(getClass().getSimpleName(), "hereeeeeeeee" + i); - - syncResult.stats.numEntries++; - - Log.i(getClass().getSimpleName(), "numEnt" + i); - - // Create local article entry - id = c.getInt(c.getColumnIndex(DatabaseContract.TodoColumns.ID)); - title = c.getString(c.getColumnIndex(DatabaseContract.TodoColumns.TITLE)); - description = c.getString(c.getColumnIndex(DatabaseContract.TodoColumns.DESCRIPTION)); - done = c.getInt(c.getColumnIndex(DatabaseContract.TodoColumns.DONE)) != 0; - - // Try to retrieve the local entry from network entries - found = todos.get(id); - if (found != null) { - Log.i(getClass().getSimpleName(), "found"); - // The entry exists, remove from hash table to prevent re-inserting it - todos.remove(id); - - // Check to see if it needs to be updated - if ( - !title.equals(found.getTitle()) || - !description.equals(found.getDescription()) || - done != found.isDone()) { - // Batch an update for the existing record - Log.i(TAG, "Scheduling update: " + title); - batch.add(ContentProviderOperation.newUpdate(DatabaseContract.getElementUri(id)) - .withSelection(DatabaseContract.TodoColumns.ID + "='" + id + "'", new String[]{Integer.toString(id)}) - .withValue(DatabaseContract.TodoColumns.TITLE, found.getTitle()) - .withValue(DatabaseContract.TodoColumns.DESCRIPTION, found.getDescription()) - .withValue(DatabaseContract.TodoColumns.DONE, found.isDone()) - .build()); - syncResult.stats.numUpdates++; - } - } else { - // Entry doesn't exist, remove it from the local database - Log.i(TAG, "Scheduling delete: " + title); - batch.add(ContentProviderOperation.newDelete(DatabaseContract.getElementUri(id)) - .withSelection(DatabaseContract.TodoColumns.ID + "='" + id + "'", new String[]{Integer.toString(id)}) - .build()); - syncResult.stats.numDeletes++; - } - c.moveToNext(); - } - c.close(); - - // Add all the new entries - for (Todo todo : todos.values()) { - Log.i(TAG, "Scheduling insert: " + todo.getTitle()); - batch.add(ContentProviderOperation.newInsert(DatabaseContract.CONTENT_URI) - .withValue(DatabaseContract.TodoColumns.TITLE, todo.getTitle()) - .withValue(DatabaseContract.TodoColumns.DESCRIPTION, todo.getDescription()) - .withValue(DatabaseContract.TodoColumns.DONE, todo.isDone()) - .build()); - syncResult.stats.numInserts++; - } - - // Synchronize by performing batch update - Log.i(TAG, "Merge solution ready, applying batch update..."); - resolver.applyBatch(DatabaseContract.CONTENT_AUTHORITY, batch); - resolver.notifyChange(DatabaseContract.CONTENT_URI, // URI where data was modified - null, // No local observer - false); // IMPORTANT: Do not sync to network - } - - /** - * Manual force Android to perform a sync with our SyncAdapter. - */ - public static void performSync() { - Bundle b = new Bundle(); - b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); - b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); - ContentResolver.requestSync(AccountGeneral.getAccount(), - DatabaseContract.CONTENT_AUTHORITY, b); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncService.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncService.java deleted file mode 100644 index 97f219f..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/SyncService.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.blink22.android.mvpandroid.data.db; - -/** - * Created by ahmedghazy on 7/31/18. - */ - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; -import android.support.annotation.Nullable; - -/** - * This is used only by Android to run our {@link SyncAdapter}. - */ -public class SyncService extends Service { - /** - * Lock use to synchronize instantiation of SyncAdapter. - */ - private static final Object LOCK = new Object(); - private static SyncAdapter syncAdapter; - - - @Override - public void onCreate() { - // SyncAdapter is not Thread-safe - synchronized (LOCK) { - // Instantiate our SyncAdapter - syncAdapter = new SyncAdapter(this, false); - } - } - - @Nullable - @Override - public IBinder onBind(Intent intent) { - // Return our SyncAdapter's IBinder - return syncAdapter.getSyncAdapterBinder(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/TodoProvider.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/TodoProvider.java deleted file mode 100644 index d5919d4..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/TodoProvider.java +++ /dev/null @@ -1,280 +0,0 @@ -package com.blink22.android.mvpandroid.data.db; - -/** - * Created by ahmedghazy on 7/31/18. - */ - -import android.app.job.JobInfo; -import android.app.job.JobScheduler; -import android.content.ComponentName; -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.UriMatcher; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.net.Uri; -import android.support.annotation.Nullable; -import android.text.format.DateUtils; -import android.util.Log; - -import io.realm.DynamicRealm; -import io.realm.Realm; -import io.realm.RealmConfiguration; -import io.realm.RealmMigration; -import io.realm.RealmResults; -import io.realm.RealmSchema; - -import com.blink22.android.mvpandroid.data.db.DatabaseContract.TodoColumns; -import com.blink22.android.mvpandroid.data.db.model.Todo; - - -public class TodoProvider extends ContentProvider { - private static final String TAG = TodoProvider.class.getSimpleName(); - - private static final int CLEANUP_JOB_ID = 43; - private static final int TODOS = 100; - private static final int TODO_WITH_ID = 101; - - private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - static { - // content://com.example.rgher.realmtodo/tasks - sUriMatcher.addURI(DatabaseContract.CONTENT_AUTHORITY, - DatabaseContract.TABLE_TODOS, - TODOS); - - // content://com.example.rgher.realmtodo/tasks/id - sUriMatcher.addURI(DatabaseContract.CONTENT_AUTHORITY, - DatabaseContract.TABLE_TODOS + "/#", - TODO_WITH_ID); - } - - - @Override - public boolean onCreate() { - - //Innitializing RealmDB - Realm.init(getContext()); - RealmConfiguration config = new RealmConfiguration.Builder() - .schemaVersion(1) - .migration(new MyRealmMigration()) - .build(); - - Realm.setDefaultConfiguration(config); - -// manageCleanupJob(); - - return true; - } - - @Nullable - @Override - public String getType(Uri uri) { - return null; /* Not used */ - } - - @Nullable - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - - int match = sUriMatcher.match(uri); - - //Get Realm Instance - Realm realm = Realm.getDefaultInstance(); - MatrixCursor myCursor = new MatrixCursor( new String[]{ - TodoColumns.ID, - TodoColumns.TITLE, - TodoColumns.DESCRIPTION, - TodoColumns.DONE - }); - - try { - switch (match) { - //Expected "query all" Uri: content://com.example.rgher.realmtodo/tasks - - case TODOS: - RealmResults todoRealmResults = realm.where(Todo.class).findAll(); - for (Todo todo : todoRealmResults) { - Log.i(getClass().getSimpleName(), "tdo: " + todo.getTitle()); - Object[] rowData = new Object[]{todo.getId(), todo.getTitle(), todo.getDescription(), todo.isDone() ? 1 : 0}; - - Log.i(getClass().getSimpleName(), "^^^" + todo.isDone()); - - myCursor.addRow(rowData); - Log.v("RealmDB", todo.toString()); - } - break; - - //Expected "query one" Uri: content://com.example.rgher.realmtodo/tasks/{id} - case TODO_WITH_ID: - Integer id = Integer.parseInt(uri.getPathSegments().get(1)); - - Todo todo = realm.where(Todo.class).equalTo(TodoColumns.ID, id).findFirst(); - myCursor.addRow(new Object[]{todo.getId(), todo.getTitle(), todo.getDescription(), todo.isDone()}); - Log.v("RealmDB", todo.toString()); - break; - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); - } - - - myCursor.setNotificationUri(getContext().getContentResolver(), uri); - } finally { - realm.close(); - } - - - - return myCursor; - - } - - @Nullable - @Override - public Uri insert(Uri uri, final ContentValues contentValues) { - //COMPLETE: Expected Uri: content://com.example.rgher.realmtodo/tasks - - //final SQLiteDatabase taskDb = mDbHelper.getReadableDatabase(); - int match = sUriMatcher.match(uri); - Uri returnUri; - - //Get Realm Instance - Realm realm = Realm.getDefaultInstance(); - try { - switch (match) { - case TODOS: - realm.executeTransaction(new Realm.Transaction() { - @Override - public void execute(Realm realm) { - - Number currId = realm.where(Todo.class).max(TodoColumns.ID); - - Integer nextId = (currId == null) ? 1 : currId.intValue() + 1; - - Todo todo = realm.createObject(Todo.class, nextId); - todo.setTitle(contentValues.getAsString(TodoColumns.TITLE)); - todo.setDescription(contentValues.getAsString(TodoColumns.DESCRIPTION)); - todo.setDone(contentValues.getAsBoolean(TodoColumns.DONE)); - } - }); - returnUri = ContentUris.withAppendedId(DatabaseContract.CONTENT_URI, '1'); - break; - - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); - } - - getContext().getContentResolver().notifyChange(uri, null); - }finally { - realm.close(); - } - return returnUri; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - - //Expected Uri: content://com.example.rgher.realmtodo/tasks/{id} - Realm realm = Realm.getDefaultInstance(); - - int match = sUriMatcher.match(uri); - int nrUpdated = 0; - try { - switch (match) { - case TODO_WITH_ID: - Integer id = Integer.parseInt(uri.getPathSegments().get(1)); - - Todo todo = realm.where(Todo.class).equalTo(TodoColumns.ID, id).findFirst(); - realm.beginTransaction(); - todo.setDone(values.getAsBoolean(TodoColumns.DONE)); - nrUpdated++; - realm.commitTransaction(); - break; - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); - } - - - } finally { - realm.close(); - } - - if (nrUpdated != 0) { - getContext().getContentResolver().notifyChange(uri, null); - } - return nrUpdated; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - int count = 0; - Realm realm = Realm.getDefaultInstance(); - try { - switch (sUriMatcher.match(uri)) { - case TODO_WITH_ID: - Integer id = Integer.parseInt(uri.getPathSegments().get(1)); - - Todo myTask = realm.where(Todo.class).equalTo(TodoColumns.ID, id).findFirst(); - realm.beginTransaction(); - if(myTask != null) { - myTask.deleteFromRealm(); - count++; - } - realm.commitTransaction(); - break; - default: - throw new IllegalArgumentException("Illegal delete URI"); - } - } finally { - realm.close(); - } - if (count > 0) { - //Notify observers of the change - getContext().getContentResolver().notifyChange(uri, null); - } - - return count; - } - -// /* Initiate a periodic job to clear out completed items */ -// private void manageCleanupJob() { -// Log.d(TAG, "Scheduling cleanup job"); -// JobScheduler jobScheduler = (JobScheduler) getContext() -// .getSystemService(Context.JOB_SCHEDULER_SERVICE); -// -// //Run the job approximately every hour -// long jobInterval = DateUtils.MINUTE_IN_MILLIS; -// -// ComponentName jobService = new ComponentName(getContext(), CleanupJobService.class); -// -// JobInfo task = new JobInfo.Builder(CLEANUP_JOB_ID, jobService) -// .setPeriodic(jobInterval) -// .setPersisted(true) -// .build(); -// -// if (jobScheduler.schedule(task) != JobScheduler.RESULT_SUCCESS) { -// Log.w(TAG, "Unable to schedule cleanup job"); -// } -// } -} - -// Example of REALM migration -class MyRealmMigration implements RealmMigration { - @Override - public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { - - RealmSchema schema = realm.getSchema(); - - if (oldVersion != 0) { - schema.create(DatabaseContract.TABLE_TODOS) - .addField(DatabaseContract.TodoColumns.ID, Integer.class) - .addField(TodoColumns.TITLE, String.class) - .addField(TodoColumns.DESCRIPTION, String.class) - .addField(TodoColumns.DONE, Boolean.class); - oldVersion++; - } - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java index 7a4756b..77887b2 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/model/Todo.java @@ -16,6 +16,7 @@ public class Todo extends RealmObject { private String title; private String description; private boolean done; + private String updatedDate; public Todo(int id) { this.id = id; @@ -64,4 +65,12 @@ public boolean isDone() { public void setDone(boolean done) { this.done = done; } + + public String getUpdatedDate() { + return updatedDate; + } + + public void setUpdatedDate(String updatedDate) { + this.updatedDate = updatedDate; + } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/models/NavigationItemEnum.java b/app/src/main/java/com/blink22/android/mvpandroid/data/model/NavigationItemEnum.java similarity index 95% rename from app/src/main/java/com/blink22/android/mvpandroid/models/NavigationItemEnum.java rename to app/src/main/java/com/blink22/android/mvpandroid/data/model/NavigationItemEnum.java index d3c3ca1..855b5a3 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/models/NavigationItemEnum.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/model/NavigationItemEnum.java @@ -1,4 +1,4 @@ -package com.blink22.android.mvpandroid.models; +package com.blink22.android.mvpandroid.data.model; import com.blink22.android.mvpandroid.R; import com.blink22.android.mvpandroid.ui.newtodo.NewTodoActivity; diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/AppPrefsHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/AppPrefsHelper.java index 80e15e0..4dbe179 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/AppPrefsHelper.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/AppPrefsHelper.java @@ -11,20 +11,21 @@ public class AppPrefsHelper implements PrefsHelper { SharedPreferences mSharedPreferences; - private static final String PREF_KEY_USER_NAME = "PREF_KEY_USER_NAME"; + private static final String PREF_KEY_SYNC_REQUIRED = "PREF_KEY_SYNC_REQUIRED"; @Inject public AppPrefsHelper(SharedPreferences sharedPreferences) { mSharedPreferences = sharedPreferences; } + @Override - public String getUserName() { - return mSharedPreferences.getString(PREF_KEY_USER_NAME, null); + public boolean isSyncDone() { + return mSharedPreferences.getBoolean(PREF_KEY_SYNC_REQUIRED, false); } @Override - public void setUserName(String userName) { - mSharedPreferences.edit().putString(PREF_KEY_USER_NAME, userName).apply(); + public void setSyncDone(boolean syncRequired) { + mSharedPreferences.edit().putBoolean(PREF_KEY_SYNC_REQUIRED, syncRequired).commit(); } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/PrefsHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/PrefsHelper.java index c73dd63..f1b6481 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/PrefsHelper.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/prefs/PrefsHelper.java @@ -5,7 +5,7 @@ */ public interface PrefsHelper { - String getUserName(); + boolean isSyncDone(); - void setUserName(String userName); + void setSyncDone(boolean syncRequired); } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/AppModule.java b/app/src/main/java/com/blink22/android/mvpandroid/di/AppModule.java deleted file mode 100644 index f8bd99c..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/AppModule.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.blink22.android.mvpandroid.di; - -import android.app.Application; - -import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; - -/** - * Created by ahmedghazy on 7/29/18. - */ - -@Module -public class AppModule { - Application mApplication; - - public AppModule(Application application) { - mApplication = application; - } - - @Provides - @Singleton - public Application providesApplication() { - return mApplication; - } -} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkComponent.java b/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkComponent.java deleted file mode 100644 index 2ace0d9..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkComponent.java +++ /dev/null @@ -1,21 +0,0 @@ -//package com.blink22.android.mvpandroid.di; -// -//import com.blink22.android.mvpandroid.ui.newtodo.NewTodoActivity; -//import com.blink22.android.mvpandroid.ui.newtodo.NewTodoFragment; -//import com.blink22.android.mvpandroid.ui.todos.TodosActivity; -//import com.blink22.android.mvpandroid.ui.todos.TodosFragment; -// -//import javax.inject.Singleton; -// -//import dagger.Component; -// -///** -// * Created by ahmedghazy on 7/29/18. -// */ -// -//@Singleton -//@Component(modules={AppModule.class, NetworkModule.class}) -//public interface NetworkComponent { -// void inject(TodosActivity todosActivity); -// void inject(NewTodoActivity newTodoActivity); -//} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkModule.java b/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkModule.java deleted file mode 100644 index 557d1b0..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/NetworkModule.java +++ /dev/null @@ -1,91 +0,0 @@ -//package com.blink22.android.mvpandroid.di; -// -//import android.app.Application; -// -//import com.blink22.android.mvpandroid.BuildConfig; -//import com.blink22.android.mvpandroid.apiinterfaces.TodosService; -//import com.blink22.android.mvpandroid.network.TodosSubscriber; -//import com.google.gson.Gson; -// -//import java.io.File; -// -//import javax.inject.Named; -//import javax.inject.Singleton; -// -//import dagger.Module; -//import dagger.Provides; -//import okhttp3.Cache; -//import okhttp3.OkHttpClient; -//import retrofit2.CallAdapter; -//import retrofit2.Retrofit; -//import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; -//import retrofit2.converter.gson.GsonConverterFactory; -// -///** -// * Created by ahmedghazy on 7/29/18. -// */ -// -//@Module -//public class NetworkModule { -// @Provides -// @Named("api_url") -// String provideApiLink() { -// return BuildConfig.BASE_URL; -// } -// -// @Provides -// @Singleton -// Cache provideOkHttpCache(Application application) { -// int cacheSize = 5 * 1024 * 1024; -// Cache cache = new Cache(application.getCacheDir(), cacheSize); -// return cache; -// } -// -// @Provides -// @Singleton -// @Named("cached") -// OkHttpClient provideOkHttpClient(Cache cache) { -// OkHttpClient okHttpClient = new OkHttpClient.Builder().cache(cache).build(); -// return okHttpClient; -// } -// -// @Provides -// @Singleton -// @Named("non_cached") -// OkHttpClient provideOkHttpClientNonCached() { -// OkHttpClient okHttpClient = new OkHttpClient(); -// return okHttpClient; -// } -// -// @Provides -// @Singleton -// @Named("rxjava2_call_adapter") -// CallAdapter.Factory provideCallAdapterFactory() { -// return RxJava2CallAdapterFactory.create(); -// } -// -// @Provides -// @Singleton -// Retrofit provideRetrofit(@Named("cached") OkHttpClient okHttpClient, -// @Named("rxjava2_call_adapter") CallAdapter.Factory rxJava2CallAdapterFactory, -// @Named("api_url") String url) { -// return new Retrofit.Builder() -// .addConverterFactory(GsonConverterFactory.create()) -// .addCallAdapterFactory(rxJava2CallAdapterFactory) -// .baseUrl(url) -// .client(okHttpClient) -// .build(); -// } -// -// @Provides -// @Singleton -// TodosService provideTodosService(Retrofit retrofit) { -// return retrofit.create(TodosService.class); -// } -// -// @Provides -// @Singleton -// TodosSubscriber provideTodosSubscriber(TodosService todosService) { -// return new TodosSubscriber(todosService); -// } -//} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/component/ActivityComponent.java b/app/src/main/java/com/blink22/android/mvpandroid/di/component/ActivityComponent.java index 3a1d9fe..6286a57 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/component/ActivityComponent.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/component/ActivityComponent.java @@ -1,6 +1,6 @@ package com.blink22.android.mvpandroid.di.component; -import com.blink22.android.mvpandroid.di.PerActivity; +import com.blink22.android.mvpandroid.di.scope.PerActivity; import com.blink22.android.mvpandroid.di.module.ActivityModule; import com.blink22.android.mvpandroid.ui.newtodo.NewTodoActivity; import com.blink22.android.mvpandroid.ui.todos.TodosActivity; @@ -14,7 +14,9 @@ @PerActivity @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { + void inject(TodosActivity todosActivity); void inject(NewTodoActivity newTodoActivity); + } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/component/ApplicationComponent.java b/app/src/main/java/com/blink22/android/mvpandroid/di/component/ApplicationComponent.java index dab8ab5..273a275 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/component/ApplicationComponent.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/component/ApplicationComponent.java @@ -18,12 +18,11 @@ @Singleton @Component(modules = ApplicationModule.class) public interface ApplicationComponent { - void inject(Application application); - @Named("application_context") - Context context(); + void inject(Application application); - Application application(); + @Named("application_context") Context getApplicationContext(); DataManager dataManager(); + } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/component/SyncAdapterComponent.java b/app/src/main/java/com/blink22/android/mvpandroid/di/component/SyncAdapterComponent.java index d31aa1e..50b1533 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/component/SyncAdapterComponent.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/component/SyncAdapterComponent.java @@ -1,10 +1,10 @@ package com.blink22.android.mvpandroid.di.component; -import com.blink22.android.mvpandroid.data.db.SyncAdapter; -import com.blink22.android.mvpandroid.di.PerSyncService; +import com.blink22.android.mvpandroid.di.scope.PerSyncService; import com.blink22.android.mvpandroid.di.module.SyncAdapterModule; +import com.blink22.android.mvpandroid.service.SyncAdapter; -import javax.inject.Singleton; +import javax.inject.Named; import dagger.Component; @@ -15,5 +15,7 @@ @PerSyncService @Component(dependencies = ApplicationComponent.class, modules = SyncAdapterModule.class) public interface SyncAdapterComponent { + void inject(SyncAdapter syncAdapter); + } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/module/ActivityModule.java b/app/src/main/java/com/blink22/android/mvpandroid/di/module/ActivityModule.java index 3bbdde0..b00bcd2 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/module/ActivityModule.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/module/ActivityModule.java @@ -2,9 +2,8 @@ import android.content.Context; import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import com.blink22.android.mvpandroid.di.PerActivity; +import com.blink22.android.mvpandroid.di.scope.PerActivity; import com.blink22.android.mvpandroid.ui.newtodo.NewTodoContract; import com.blink22.android.mvpandroid.ui.newtodo.NewTodoPresenter; import com.blink22.android.mvpandroid.ui.todos.TodosContract; diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/module/SyncAdapterModule.java b/app/src/main/java/com/blink22/android/mvpandroid/di/module/SyncAdapterModule.java index 3ed002c..4ca361c 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/module/SyncAdapterModule.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/module/SyncAdapterModule.java @@ -1,6 +1,12 @@ package com.blink22.android.mvpandroid.di.module; -import com.blink22.android.mvpandroid.data.db.SyncAdapter; +import android.content.Context; + +import com.blink22.android.mvpandroid.R; +import com.blink22.android.mvpandroid.service.SyncAdapter; + +import javax.inject.Inject; +import javax.inject.Named; import dagger.Module; import dagger.Provides; @@ -11,6 +17,7 @@ @Module public class SyncAdapterModule { + @Inject SyncAdapter mSyncAdapter; public SyncAdapterModule(SyncAdapter syncAdapter) { diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/PerActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/di/scope/PerActivity.java similarity index 82% rename from app/src/main/java/com/blink22/android/mvpandroid/di/PerActivity.java rename to app/src/main/java/com/blink22/android/mvpandroid/di/scope/PerActivity.java index 8f68ffd..fadbe9c 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/PerActivity.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/scope/PerActivity.java @@ -1,4 +1,4 @@ -package com.blink22.android.mvpandroid.di; +package com.blink22.android.mvpandroid.di.scope; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/app/src/main/java/com/blink22/android/mvpandroid/di/PerSyncService.java b/app/src/main/java/com/blink22/android/mvpandroid/di/scope/PerSyncService.java similarity index 83% rename from app/src/main/java/com/blink22/android/mvpandroid/di/PerSyncService.java rename to app/src/main/java/com/blink22/android/mvpandroid/di/scope/PerSyncService.java index 05b6faa..aa76d8b 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/di/PerSyncService.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/di/scope/PerSyncService.java @@ -1,4 +1,4 @@ -package com.blink22.android.mvpandroid.di; +package com.blink22.android.mvpandroid.di.scope; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/app/src/main/java/com/blink22/android/mvpandroid/network/NetworkManager.java b/app/src/main/java/com/blink22/android/mvpandroid/network/NetworkManager.java deleted file mode 100755 index a59f1f6..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/network/NetworkManager.java +++ /dev/null @@ -1,53 +0,0 @@ -//package com.blink22.android.mvpandroid.network; -// -//import com.blink22.android.mvpandroid.BuildConfig; -//import com.blink22.android.mvpandroid.apiinterfaces.TodosService; -// -//import java.io.IOException; -// -//import okhttp3.Interceptor; -//import okhttp3.OkHttpClient; -//import okhttp3.Request; -//import retrofit2.Retrofit; -//import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; -//import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; -//import retrofit2.converter.gson.GsonConverterFactory; -//import retrofit2.converter.scalars.ScalarsConverterFactory; -// -///** -// * Created by ahmedghazy on 7/25/18. -// */ -// -//public class NetworkManager { -// private static final String TAG = NetworkManager.class.getSimpleName(); -// -// private static NetworkManager sNetworkManager; -// -// private TodosService mTodosService; -// -// private NetworkManager() { -// // Required private constructor for singleton class -// } -// -// public static NetworkManager getInstance() { -// if (sNetworkManager == null) { -// sNetworkManager = new NetworkManager(); -// } -// -// return sNetworkManager; -// } -// -// public TodosService getTodosService() { -// if (mTodosService == null) { -// mTodosService = new Retrofit -// .Builder() -// .baseUrl(BuildConfig.BASE_URL) -// .addConverterFactory(GsonConverterFactory.create()) -// .addConverterFactory(ScalarsConverterFactory.create()) -// .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) -// .build() -// .create(TodosService.class); -// } -// return mTodosService; -// } -//} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/network/TodosSubscriber.java b/app/src/main/java/com/blink22/android/mvpandroid/network/TodosSubscriber.java deleted file mode 100755 index 142ae82..0000000 --- a/app/src/main/java/com/blink22/android/mvpandroid/network/TodosSubscriber.java +++ /dev/null @@ -1,105 +0,0 @@ -//package com.blink22.android.mvpandroid.network; -// -//import com.blink22.android.mvpandroid.apiinterfaces.TodosService; -//import com.blink22.android.mvpandroid.data.db.model.Todo; -// -//import java.util.ArrayList; -// -//import io.reactivex.android.schedulers.AndroidSchedulers; -//import io.reactivex.observers.DisposableObserver; -//import io.reactivex.schedulers.Schedulers; -// -///** -// * Created by ahmedghazy on 7/26/18. -// */ -// -//public class TodosSubscriber { -// -// private static final String TAG = TodosSubscriber.class.getSimpleName(); -// -// private final TodosService mTodosService; -// -// public TodosSubscriber(TodosService todosService) { -// mTodosService = todosService; -// } -// -// public DisposableObserver> getTodos(final Callback> callback) { -// -// return mTodosService -// .getTodos() -// .subscribeOn(Schedulers.io()) -// .observeOn(AndroidSchedulers.mainThread()) -// .subscribeWith(new DisposableObserver>() { -// @Override -// public void onNext(ArrayList todos) { -// callback.onSuccess(todos); -// } -// -// @Override -// public void onError(Throwable e) { -// callback.onError(new Exception(e)); -// } -// -// @Override -// public void onComplete() { -// -// } -// }); -// } -// -// public DisposableObserver createTodo(final Callback callback, Todo todo) { -// -// return mTodosService -// .createTodo(todo) -// .subscribeOn(Schedulers.io()) -// .observeOn(AndroidSchedulers.mainThread()) -// .subscribeWith(new DisposableObserver() { -// @Override -// public void onNext(Todo todo) { -// callback.onSuccess(todo); -// } -// -// @Override -// public void onError(Throwable e) { -// callback.onError(new Exception(e)); -// } -// -// @Override -// public void onComplete() { -// -// } -// }); -// } -// -// public DisposableObserver updateTodo(final Callback callback, Todo todo) { -// -// return mTodosService -// .updateTodo(todo.getId(), todo) -// .subscribeOn(Schedulers.io()) -// .observeOn(AndroidSchedulers.mainThread()) -// .subscribeWith(new DisposableObserver() { -// @Override -// public void onNext(Todo todo) { -// callback.onSuccess(todo); -// } -// -// @Override -// public void onError(Throwable e) { -// callback.onError(new Exception(e)); -// } -// -// @Override -// public void onComplete() { -// -// } -// }); -// } -// -// public interface Callback { -// void onSuccess(T ret); -// -// // Investigate what kind of exception -// void onError(Exception e); -// } -// -//} diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountAuthenticator.java b/app/src/main/java/com/blink22/android/mvpandroid/service/AccountAuthenticator.java similarity index 97% rename from app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountAuthenticator.java rename to app/src/main/java/com/blink22/android/mvpandroid/service/AccountAuthenticator.java index 6dac63d..ff75b7a 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AccountAuthenticator.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/service/AccountAuthenticator.java @@ -1,4 +1,4 @@ -package com.blink22.android.mvpandroid.data.db; +package com.blink22.android.mvpandroid.service; /** * Created by ahmedghazy on 7/31/18. diff --git a/app/src/main/java/com/blink22/android/mvpandroid/service/AccountGeneral.java b/app/src/main/java/com/blink22/android/mvpandroid/service/AccountGeneral.java new file mode 100644 index 0000000..06d788a --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/service/AccountGeneral.java @@ -0,0 +1,42 @@ +package com.blink22.android.mvpandroid.service; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.ContentResolver; +import android.content.Context; +import android.os.Bundle; + +import com.blink22.android.mvpandroid.R; +import com.blink22.android.mvpandroid.utils.AppConstants; + +import javax.inject.Inject; +import javax.inject.Named; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +public final class AccountGeneral { + + public static Account getAccount(Context c) { + return new Account(c.getResources().getString(R.string.content_authority), c.getResources().getString(R.string.account_type)); + } + + public static void createSyncAccount(Context c) { + // Flag to determine if this is a new account or not + boolean created = false; + + // Get an account and the account manager + Account account = getAccount(c); + AccountManager manager = (AccountManager)c.getSystemService(Context.ACCOUNT_SERVICE); + + // Attempt to explicitly create the account with no password or extra data + if (manager.addAccountExplicitly(account, null, null)) { + ContentResolver.setIsSyncable(account, c.getResources().getString(R.string.content_authority), 1); + ContentResolver.setSyncAutomatically(account, c.getResources().getString(R.string.content_authority), true); + ContentResolver.addPeriodicSync(account, c.getResources().getString(R.string.content_authority), new Bundle(), AppConstants.APP_SYNC_FREQUENCY); + + created = true; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AuthenticatorService.java b/app/src/main/java/com/blink22/android/mvpandroid/service/AuthenticatorService.java similarity index 78% rename from app/src/main/java/com/blink22/android/mvpandroid/data/db/AuthenticatorService.java rename to app/src/main/java/com/blink22/android/mvpandroid/service/AuthenticatorService.java index 61c08e5..713f761 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AuthenticatorService.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/service/AuthenticatorService.java @@ -1,4 +1,4 @@ -package com.blink22.android.mvpandroid.data.db; +package com.blink22.android.mvpandroid.service; /** * Created by ahmedghazy on 7/31/18. @@ -9,6 +9,8 @@ import android.os.IBinder; import android.support.annotation.Nullable; +import com.blink22.android.mvpandroid.service.AccountAuthenticator; + /** * This is used only by Android to run our {@link AccountAuthenticator}. */ @@ -18,14 +20,12 @@ public class AuthenticatorService extends Service { @Override public void onCreate() { - // Instantiate our authenticator when the service is created this.authenticator = new AccountAuthenticator(this); } @Nullable @Override public IBinder onBind(Intent intent) { - // Return the authenticator's IBinder return authenticator.getIBinder(); } } \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/service/SyncAdapter.java b/app/src/main/java/com/blink22/android/mvpandroid/service/SyncAdapter.java new file mode 100644 index 0000000..9b4314e --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/service/SyncAdapter.java @@ -0,0 +1,63 @@ +package com.blink22.android.mvpandroid.service; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +import android.accounts.Account; +import android.content.AbstractThreadedSyncAdapter; +import android.content.ContentProviderClient; +import android.content.ContentResolver; +import android.content.Context; +import android.content.SyncResult; +import android.os.Bundle; + +import com.blink22.android.mvpandroid.BaseApp; +import com.blink22.android.mvpandroid.R; +import com.blink22.android.mvpandroid.data.DataManager; +import com.blink22.android.mvpandroid.di.scope.PerSyncService; +import com.blink22.android.mvpandroid.di.component.DaggerSyncAdapterComponent; +import com.blink22.android.mvpandroid.di.component.SyncAdapterComponent; +import com.blink22.android.mvpandroid.di.module.SyncAdapterModule; +import com.blink22.android.mvpandroid.utils.AppConstants; + +import javax.inject.Inject; +import javax.inject.Named; + + +@PerSyncService +public class SyncAdapter extends AbstractThreadedSyncAdapter { + @Inject DataManager mDataManager; + + public SyncAdapter(Context c, boolean autoInit) { + super(c, autoInit); + initialize(c); + } + + public SyncAdapter(Context c, boolean autoInit, boolean parallelSync) { + super(c, autoInit, parallelSync); + initialize(c); + + } + + void initialize(Context c) { + SyncAdapterComponent component = DaggerSyncAdapterComponent.builder() + .applicationComponent(((BaseApp)c.getApplicationContext()).getComponent()) + .syncAdapterModule(new SyncAdapterModule(this)) + .build(); + component.inject(this); + } + + @Override + public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { + mDataManager.syncData(); + } + + public static void performSync(Context c) { + Bundle b = new Bundle(); + b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); + ContentResolver.requestSync(AccountGeneral.getAccount(c), + c.getResources().getString(R.string.content_authority), b); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/service/SyncService.java b/app/src/main/java/com/blink22/android/mvpandroid/service/SyncService.java new file mode 100644 index 0000000..66a7ea9 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/service/SyncService.java @@ -0,0 +1,33 @@ +package com.blink22.android.mvpandroid.service; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.support.annotation.Nullable; + +/** + * This is used only by Android to run our {@link SyncAdapter}. + */ +public class SyncService extends Service { + private static final Object sSyncAdapterLock = new Object(); + private static SyncAdapter sSyncAdapter = null; + + @Override + public void onCreate() { + synchronized (sSyncAdapterLock) { + if (sSyncAdapter == null) { + sSyncAdapter = new SyncAdapter(getApplicationContext(), true); + } + } + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return sSyncAdapter.getSyncAdapterBinder(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/service/TodoProvider.java b/app/src/main/java/com/blink22/android/mvpandroid/service/TodoProvider.java new file mode 100644 index 0000000..e23b6e7 --- /dev/null +++ b/app/src/main/java/com/blink22/android/mvpandroid/service/TodoProvider.java @@ -0,0 +1,65 @@ +package com.blink22.android.mvpandroid.service; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; + +/** + * Created by ahmedghazy on 7/31/18. + */ + +public class TodoProvider extends ContentProvider { + /* + * Always return true, indicating that the + * provider loaded correctly. + */ + @Override + public boolean onCreate() { + return true; + } + /* + * Return no type for MIME type + */ + @Override + public String getType(Uri uri) { + return null; + } + /* + * query() always returns no results + * + */ + @Override + public Cursor query( + Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { + return null; + } + /* + * insert() always returns null (no URI) + */ + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + /* + * delete() always returns "no rows affected" (0) + */ + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + /* + * update() always returns "no rows affected" (0) + */ + public int update( + Uri uri, + ContentValues values, + String selection, + String[] selectionArgs) { + return 0; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java index 18d9efc..4bd88ff 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BaseActivity.java @@ -6,26 +6,22 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.os.PersistableBundle; import android.support.annotation.Nullable; import android.support.design.widget.NavigationView; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import com.blink22.android.mvpandroid.BaseApp; import com.blink22.android.mvpandroid.R; -import com.blink22.android.mvpandroid.data.db.AccountGeneral; -import com.blink22.android.mvpandroid.data.db.DatabaseContract; -import com.blink22.android.mvpandroid.data.db.SyncAdapter; +import com.blink22.android.mvpandroid.service.AccountGeneral; import com.blink22.android.mvpandroid.di.component.ActivityComponent; import com.blink22.android.mvpandroid.di.component.DaggerActivityComponent; import com.blink22.android.mvpandroid.di.module.ActivityModule; -import com.blink22.android.mvpandroid.models.NavigationItemEnum; +import com.blink22.android.mvpandroid.data.model.NavigationItemEnum; import butterknife.BindView; import butterknife.ButterKnife; @@ -35,80 +31,35 @@ */ public abstract class BaseActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { - protected abstract Fragment createFragment(); @BindView(R.id.drawer_layout) DrawerLayout mDrawerLayout; @BindView(R.id.nav_view) NavigationView navigationView; - - private TodosObserver mTodosObserver; - - public ActivityComponent getActivityComponent() { - return mActivityComponent; - } - private ActivityComponent mActivityComponent; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mActivityComponent = DaggerActivityComponent.builder() .applicationComponent(((BaseApp) getApplication()).getComponent()) .activityModule(new ActivityModule(this)) .build(); - setContentView(R.layout.activity_fragment); ButterKnife.bind(this); - - navigationView.setNavigationItemSelectedListener(this); - - Menu menu = navigationView.getMenu(); - - for(NavigationItemEnum item: NavigationItemEnum.values()) { - MenuItem menuItem = menu.add(R.id.nav_group, item.getId(), Menu.NONE, item.getLabelResourceId()); - menuItem.setIcon(item.getIconResourceId()); - } - - FragmentManager fm = getSupportFragmentManager(); - Fragment fragment = fm.findFragmentById(R.id.fragment_container); - - if(fragment == null) { - fragment = createFragment(); - fm.beginTransaction() - .add(R.id.fragment_container, fragment) - .commit(); - } - - // Create your sync account - AccountGeneral.createSyncAccount(this); - - // Perform a manual sync by calling this: - SyncAdapter.performSync(); - - - // Setup example content observer - mTodosObserver = new TodosObserver(); + setupDrawerMenu(); + setupContentFragment(); } @Override protected void onStart() { super.onStart(); - - // Register the observer at the start of our activity - getContentResolver().registerContentObserver( - DatabaseContract.CONTENT_URI, // Uri to observe (our articles) - true, // Observe its descendants - mTodosObserver); // The observer } @Override protected void onStop() { super.onStop(); + } - - if (mTodosObserver != null) { - // Unregister the observer at the stop of our activity - getContentResolver().unregisterContentObserver(mTodosObserver); - } + public ActivityComponent getActivityComponent() { + return mActivityComponent; } public boolean onNavigationItemSelected(MenuItem menuItem) { @@ -116,29 +67,37 @@ public boolean onNavigationItemSelected(MenuItem menuItem) { for(NavigationItemEnum item: NavigationItemEnum.values()) { if(item.getId() == menuItem.getItemId()) { - Intent i = new Intent(getApplicationContext(), item.getClassToLaunch()); - i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(i); + Intent selectedDrawerItemIntent = new Intent(this, item.getClassToLaunch()); + selectedDrawerItemIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(selectedDrawerItemIntent); } } return true; } - private void refreshArticles() { - Log.i(getClass().getName(), "Articles data has changed!"); - } + private void setupDrawerMenu() { + navigationView.setNavigationItemSelectedListener(this); + + Menu menu = navigationView.getMenu(); - private final class TodosObserver extends ContentObserver { - private TodosObserver() { - // Ensure callbacks happen on the UI thread - super(new Handler(Looper.getMainLooper())); + for(NavigationItemEnum item: NavigationItemEnum.values()) { + MenuItem menuItem = menu.add(R.id.nav_group, item.getId(), Menu.NONE, item.getLabelResourceId()); + menuItem.setIcon(item.getIconResourceId()); } + } + + private void setupContentFragment() { + FragmentManager fm = getSupportFragmentManager(); + Fragment fragment = fm.findFragmentById(R.id.fragment_container); - @Override - public void onChange(boolean selfChange, Uri uri) { - // Handle your data changes here!!! - refreshArticles(); + if(fragment == null) { + fragment = createFragment(); + fm.beginTransaction() + .add(R.id.fragment_container, fragment) + .commit(); } } + + protected abstract Fragment createFragment(); } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BasePresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BasePresenter.java index 04b39ca..99d026c 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BasePresenter.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/BasePresenter.java @@ -3,10 +3,13 @@ import android.arch.lifecycle.Lifecycle; import android.arch.lifecycle.LifecycleObserver; import android.arch.lifecycle.OnLifecycleEvent; +import android.content.Context; import com.blink22.android.mvpandroid.data.DataManager; +import com.blink22.android.mvpandroid.service.AccountGeneral; import javax.inject.Inject; +import javax.inject.Named; import io.reactivex.disposables.CompositeDisposable; @@ -16,16 +19,33 @@ public class BasePresenter implements IBasePresenter, LifecycleObserver { + private final Context mAppContext; private final DataManager mDataManager; private final CompositeDisposable mCompositeDisposable; private V mView; @Inject - public BasePresenter(DataManager dataManager, CompositeDisposable compositeDisposable) { + public BasePresenter(@Named("application_context") Context appContext, DataManager dataManager, CompositeDisposable compositeDisposable) { + mAppContext = appContext; mDataManager = dataManager; mCompositeDisposable = compositeDisposable; } + @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) + protected void onCreate() { + AccountGeneral.createSyncAccount(mAppContext); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) + protected void onDestroy() { + mCompositeDisposable.dispose(); + mView = null; + } + + public void onAttach(V view) { + mView = view; + } + public DataManager getDataManager() { return mDataManager; } @@ -38,17 +58,7 @@ public V getView() { return mView; } - public void onAttach(V view) { - mView = view; - } - - @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) - public void onCreate() { - - } - - @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) - public void onDestroy() { - mCompositeDisposable.dispose(); + public Context getAppContext() { + return mAppContext; } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBasePresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBasePresenter.java index 3a5375e..7a62381 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBasePresenter.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/base/IBasePresenter.java @@ -8,6 +8,6 @@ public interface IBasePresenter extends LifecycleObserver{ - public void onAttach(V view); + void onAttach(V view); } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoActivity.java index 730196b..3e09722 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoActivity.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoActivity.java @@ -17,11 +17,6 @@ public class NewTodoActivity extends BaseActivity { @Inject NewTodoContract.Presenter mPresenter; - @Override - protected Fragment createFragment() { - return NewTodoFragment.newInstance(); - } - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -38,7 +33,12 @@ protected void onDestroy() { getLifecycle().removeObserver(mPresenter); } - public NewTodoContract.Presenter getPresenter() { + public NewTodoContract.Presenter getPresenter() { return mPresenter; } + + @Override + protected Fragment createFragment() { + return NewTodoFragment.newInstance(); + } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoContract.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoContract.java index 48f64d0..7877e59 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoContract.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoContract.java @@ -1,6 +1,6 @@ package com.blink22.android.mvpandroid.ui.newtodo; -import com.blink22.android.mvpandroid.di.PerActivity; +import com.blink22.android.mvpandroid.di.scope.PerActivity; import com.blink22.android.mvpandroid.ui.base.IBasePresenter; import com.blink22.android.mvpandroid.ui.base.IBaseView; @@ -12,7 +12,11 @@ public interface NewTodoContract { interface View extends IBaseView { String getTitle(); + String getDescription(); + + void showToastWithMessage(int resId); + void terminate(); } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java index 08b2451..bfdab20 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java @@ -3,13 +3,14 @@ import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; +import android.widget.Toast; import com.blink22.android.mvpandroid.R; import com.blink22.android.mvpandroid.ui.base.BaseActivity; @@ -19,60 +20,50 @@ import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.OnClick; /** * Created by ahmedghazy on 7/26/18. */ public class NewTodoFragment extends Fragment implements NewTodoContract.View { - private static final String TAG = NewTodoFragment.class.getSimpleName(); - - @BindView(R.id.new_todo_title) - TextView mTitle; - @BindView(R.id.new_todo_description) - TextView mDescription; - @BindView(R.id.new_todo_submit) - Button mSubmit; + @BindView(R.id.new_todo_title) TextView mTitle; + @BindView(R.id.new_todo_description) TextView mDescription; + @BindView(R.id.new_todo_submit) Button mSubmit; + @OnClick(R.id.new_todo_submit) + public void submit() { + mNewTodoPresenter.createTodo(); + } + private NewTodoContract.Presenter mNewTodoPresenter; + private View mView; public static NewTodoFragment newInstance() { - - Bundle args = new Bundle(); - - NewTodoFragment fragment = new NewTodoFragment(); - fragment.setArguments(args); - return fragment; + return new NewTodoFragment(); } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - } - - @Override - public void onDestroy() { - super.onDestroy(); + mNewTodoPresenter = ((NewTodoActivity) getActivity()).getPresenter(); } @Nullable @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View v = inflater.inflate(R.layout.fragment_new_todo, container, false); ButterKnife.bind(this, v); - - ((NewTodoActivity) getActivity()).getPresenter().onAttach(this); - - mSubmit.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ((NewTodoActivity) getActivity()).getPresenter().createTodo(); - } - }); + mNewTodoPresenter.onAttach(this); + mView = v; return v; } + @Override + public void onDestroy() { + super.onDestroy(); + } + @Override public String getTitle() { return mTitle.getText().toString(); @@ -83,13 +74,17 @@ public String getDescription() { return mDescription.getText().toString(); } + @Override + public void showToastWithMessage(int resId) { + Toast.makeText(getContext(), resId, Toast.LENGTH_LONG).show(); + } + @Override public void terminate() { try { getActivity().finish(); } catch (NullPointerException e) { - Log.i(TAG, e.getMessage()); - } + } } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java index a3bd632..2137d35 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java @@ -2,13 +2,18 @@ import android.arch.lifecycle.Lifecycle; import android.arch.lifecycle.OnLifecycleEvent; +import android.content.Context; +import com.blink22.android.mvpandroid.R; import com.blink22.android.mvpandroid.data.DataManager; import com.blink22.android.mvpandroid.data.db.model.Todo; import com.blink22.android.mvpandroid.ui.base.BasePresenter; import com.blink22.android.mvpandroid.ui.todos.TodosPresenter; +import java.util.Date; + import javax.inject.Inject; +import javax.inject.Named; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; @@ -24,43 +29,38 @@ public class NewTodoPresenter extends BasePresen private static final String TAG = TodosPresenter.class.getSimpleName(); @Inject - public NewTodoPresenter(DataManager dataManager, CompositeDisposable compositeDisposable) { - super(dataManager,compositeDisposable); + public NewTodoPresenter(@Named("application_context") Context context, DataManager dataManager, CompositeDisposable compositeDisposable) { + super(context, dataManager,compositeDisposable); } @Override public void createTodo() { - - Todo todo = new Todo(); - todo.setTitle(getView().getTitle()); - todo.setDescription(getView().getDescription()); - - getCompositeDisposable().add( getDataManager().saveTodo(todo).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribeWith(new DisposableObserver() { - @Override - public void onNext(Todo todo) { - getView().terminate(); - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - }) ); - - } - - @Override - public void onCreate() { - - } - - @Override - public void onDestroy() { - + if(getView() != null) { + Todo todo = new Todo(); + todo.setTitle(getView().getTitle()); + todo.setDescription(getView().getDescription()); + todo.setUpdatedDate(new Date().toString()); + getCompositeDisposable().add(getDataManager() + .saveTodo(todo) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(new DisposableObserver() { + @Override + public void onNext(Todo todo) { + getView().showToastWithMessage(R.string.create_todo_success); + getView().terminate(); + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + + } + })); + } } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosActivity.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosActivity.java index 8d40124..520a840 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosActivity.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosActivity.java @@ -1,10 +1,15 @@ package com.blink22.android.mvpandroid.ui.todos; +import android.database.ContentObserver; +import android.net.Uri; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import com.blink22.android.mvpandroid.BaseApp; +import com.blink22.android.mvpandroid.service.AccountGeneral; import com.blink22.android.mvpandroid.ui.base.BaseActivity; import javax.inject.Inject; @@ -14,12 +19,7 @@ */ public class TodosActivity extends BaseActivity{ - @Inject TodosContract.Presenter mPresenter; - - @Override - protected Fragment createFragment() { - return TodosFragment.newInstance(); - } + @Inject TodosPresenter mPresenter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -28,6 +28,18 @@ public void onCreate(@Nullable Bundle savedInstanceState) { getActivityComponent().inject(this); getLifecycle().addObserver(mPresenter); + + + } + + @Override + protected void onStart() { + super.onStart(); + } + + @Override + protected void onStop() { + super.onStop(); } @Override @@ -37,7 +49,13 @@ protected void onDestroy() { getLifecycle().removeObserver(mPresenter); } - public TodosContract.Presenter getPresenter() { + public TodosPresenter getPresenter() { return mPresenter; } + + @Override + protected Fragment createFragment() { + return TodosFragment.newInstance(); + } + } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/adapters/TodosAdapter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosAdapter.java similarity index 73% rename from app/src/main/java/com/blink22/android/mvpandroid/adapters/TodosAdapter.java rename to app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosAdapter.java index 20b7532..2bb0227 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/adapters/TodosAdapter.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosAdapter.java @@ -1,6 +1,7 @@ -package com.blink22.android.mvpandroid.adapters; +package com.blink22.android.mvpandroid.ui.todos; import android.content.Context; +import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -8,7 +9,6 @@ import com.blink22.android.mvpandroid.R; import com.blink22.android.mvpandroid.data.db.model.Todo; -import com.blink22.android.mvpandroid.viewHolders.TodosVH; import java.util.ArrayList; @@ -21,19 +21,20 @@ public class TodosAdapter extends RecyclerView.Adapter { private final OnItemClickListener mListener; private ArrayList mData; - public TodosAdapter(Context context, ArrayList data, OnItemClickListener listener) { + TodosAdapter(Context context, ArrayList data, OnItemClickListener listener) { mData = data; mListener = listener; } @Override - public TodosVH onCreateViewHolder(ViewGroup parent, int viewType) { + @NonNull + public TodosVH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_todos, null); return new TodosVH(view); } @Override - public void onBindViewHolder(TodosVH holder, int position) { + public void onBindViewHolder(@NonNull TodosVH holder, int position) { holder.bind(mData.get(position), mListener); } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosContract.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosContract.java index 9d536a6..524f1b0 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosContract.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosContract.java @@ -1,7 +1,7 @@ package com.blink22.android.mvpandroid.ui.todos; import com.blink22.android.mvpandroid.data.db.model.Todo; -import com.blink22.android.mvpandroid.di.PerActivity; +import com.blink22.android.mvpandroid.di.scope.PerActivity; import com.blink22.android.mvpandroid.ui.base.IBasePresenter; import com.blink22.android.mvpandroid.ui.base.IBaseView; diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java index 3eb65cd..68cd295 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java @@ -6,22 +6,16 @@ import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.Toast; -import com.blink22.android.mvpandroid.adapters.TodosAdapter; - import java.util.ArrayList; import com.blink22.android.mvpandroid.R; import com.blink22.android.mvpandroid.data.db.model.Todo; -import com.blink22.android.mvpandroid.ui.base.BaseActivity; - -import javax.inject.Inject; import butterknife.BindView; import butterknife.ButterKnife; @@ -31,24 +25,19 @@ */ public class TodosFragment extends Fragment implements TodosContract.View { + private static final String TAG = TodosActivity.class.getSimpleName(); @BindView(R.id.todos_list) RecyclerView mTodos; @BindView(R.id.todos_progress) ProgressBar mProgressBar; + private TodosPresenter mTodosPresenter; public static TodosFragment newInstance() { - - Bundle args = new Bundle(); - - TodosFragment fragment = new TodosFragment(); - fragment.setArguments(args); - return fragment; + return new TodosFragment(); } - private static final String TAG = TodosActivity.class.getSimpleName(); - @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + mTodosPresenter = ((TodosActivity) getActivity()).getPresenter(); } @Nullable @@ -56,25 +45,15 @@ public void onCreate(@Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View v = inflater.inflate(R.layout.todos_fragment, container, false); - ButterKnife.bind(this, v); - - ((TodosActivity) getActivity()).getPresenter().onAttach(this); - + mTodosPresenter.onAttach(this); mTodos.setLayoutManager(new LinearLayoutManager(getActivity())); - return v; } @Override public void onResume() { super.onResume(); - ((TodosActivity) getActivity()).getPresenter().getTodos(); - } - - @Override - public void onDestroy() { - super.onDestroy(); } @Override @@ -95,8 +74,6 @@ public void onFailure(String appErrorMessage) { @Override public void onGetTodosSuccess(ArrayList todos) { - Log.i(TAG, "here"); - Log.i(TAG, todos.size() + ""); TodosAdapter adapter = new TodosAdapter(getActivity().getApplicationContext(), todos, new TodosAdapter.OnItemClickListener() { @Override @@ -104,7 +81,6 @@ public void onClick(Todo item) { ((TodosActivity) getActivity()).getPresenter().updateTodo(item); } }); - mTodos.setAdapter(adapter); } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java index 6f48921..06d47eb 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java @@ -1,9 +1,14 @@ package com.blink22.android.mvpandroid.ui.todos; +import android.arch.lifecycle.Lifecycle; +import android.arch.lifecycle.LifecycleObserver; +import android.arch.lifecycle.OnLifecycleEvent; +import android.content.Context; import android.util.Log; import com.blink22.android.mvpandroid.data.DataManager; import com.blink22.android.mvpandroid.data.db.model.Todo; +import com.blink22.android.mvpandroid.service.SyncAdapter; import com.blink22.android.mvpandroid.ui.base.BasePresenter; import java.util.ArrayList; @@ -11,6 +16,7 @@ import java.util.Observer; import javax.inject.Inject; +import javax.inject.Named; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; @@ -26,52 +32,66 @@ public class TodosPresenter extends BasePresenter< private static final String TAG = TodosPresenter.class.getSimpleName(); @Inject - public TodosPresenter(DataManager dataManager, CompositeDisposable compositeDisposable) { - super(dataManager, compositeDisposable); + public TodosPresenter(@Named("application_context") Context context, DataManager dataManager, CompositeDisposable compositeDisposable) { + super(context, dataManager, compositeDisposable); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) + public void onCreate() { + super.onCreate(); + if(!getDataManager().isSyncDone()) { + SyncAdapter.performSync(getAppContext()); + getDataManager().setSyncDone(true); + } + } + + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + public void onResume() { + getTodos(); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) + void onDestry() { + super.onDestroy(); } @Override public void getTodos() { + if(getView() != null) { + getView().showWait(); + getCompositeDisposable().add(getDataManager() + .getTodos() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(new DisposableObserver>() { + @Override + public void onNext(ArrayList todos) { + getView().onGetTodosSuccess(todos); + getView().removeWait(); + } - getView().showWait(); + @Override + public void onError(Throwable e) { + getView().onFailure(e.getMessage()); + } + @Override + public void onComplete() { - getCompositeDisposable().add(getDataManager() - .getTodos() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(new DisposableObserver>() { - @Override - public void onNext(ArrayList todos) { - getView().onGetTodosSuccess(todos); - getView().removeWait(); - } - - @Override - public void onError(Throwable e) { - getView().onFailure(e.getMessage()); - Log.i(TAG, e.getLocalizedMessage()); - } - - @Override - public void onComplete() { - - } - } - ) - ); + } + }) + ); + } } @Override public void updateTodo(Todo todo) { todo.setDone(!todo.isDone()); - getCompositeDisposable().add( getDataManager() .updateTodo(todo.getId(), todo) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribeWith(new DisposableObserver( - ) { @Override public void onNext(Todo todo) { @@ -87,7 +107,7 @@ public void onError(Throwable e) { public void onComplete() { } - })); + }) + ); } - } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/viewHolders/TodosVH.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosVH.java similarity index 72% rename from app/src/main/java/com/blink22/android/mvpandroid/viewHolders/TodosVH.java rename to app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosVH.java index 3913662..db1a76e 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/viewHolders/TodosVH.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosVH.java @@ -1,4 +1,4 @@ -package com.blink22.android.mvpandroid.viewHolders; +package com.blink22.android.mvpandroid.ui.todos; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -7,9 +7,10 @@ import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.OnClick; import com.blink22.android.mvpandroid.R; -import com.blink22.android.mvpandroid.adapters.TodosAdapter; +import com.blink22.android.mvpandroid.ui.todos.TodosAdapter; import com.blink22.android.mvpandroid.data.db.model.Todo; /** @@ -21,6 +22,12 @@ public class TodosVH extends RecyclerView.ViewHolder { @BindView(R.id.todo_title) TextView mTitle; @BindView(R.id.todo_description) TextView mDescription; @BindView(R.id.todo_checkbox) CheckBox mDone; + TodosAdapter.OnItemClickListener mListener; + Todo mTodo; + @OnClick(R.id.todo_checkbox) + void check() { + mListener.onClick(mTodo); + } public TodosVH(View itemView) { super(itemView); @@ -31,12 +38,7 @@ public void bind(final Todo todo, final TodosAdapter.OnItemClickListener listene mTitle.setText(todo.getTitle()); mDescription.setText(todo.getDescription()); mDone.setChecked(todo.isDone()); - mDone.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - listener.onClick(todo); - } - }); + mListener = listener; + mTodo = todo; } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/utils/AppConstants.java b/app/src/main/java/com/blink22/android/mvpandroid/utils/AppConstants.java index 015ae16..2834517 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/utils/AppConstants.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/utils/AppConstants.java @@ -10,4 +10,6 @@ public final class AppConstants { public static final int CACHE_SIZE = 5 * 1024 * 1024; + public static final int APP_SYNC_FREQUENCY = 5 * 60; // in sec + } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9407bf1..824979c 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,8 +1,12 @@ - Playground + androidMvp Show all New one Title Description Submit + com.blink22.android.mvpandroid + com.blink22.android.mvpandroid + SyncAccount + Todo created successfuly diff --git a/db.json b/db.json index d2a0ca5..32fb679 100644 --- a/db.json +++ b/db.json @@ -1,160 +1,158 @@ { "todos": [ { - "details": "Go to the market to buy carrots", - "done": true, - "id": 1, - "title": "Buy grocery" - }, - { - "details": "Chat with your friends about last night match", - "done": false, - "id": 2, - "title": "Chat with friends" - }, - { - "details": "Call the customer service", + "id": 100, + "title": "Hello world", + "description": "Hello world", "done": false, - "id": 3, - "title": "Fix the refrigerator" + "updatedDate": "Tue Jul 31 14:57:33 GMT 2018" }, { - "id": 4, - "title": "Buy grocery", - "details": "Go to the market to buy carrots", - "done": false + "description": "Description", + "done": true, + "id": 1, + "title": "Title", + "updatedDate": "Tue Jul 31 10:25:23 EDT 2018" }, { - "details": "Chat with your friends about last night match", + "description": "Description", "done": false, - "id": 5, - "title": "Chat with friends" + "id": 13, + "title": "Title", + "updatedDate": "Tue Jul 31 10:25:39 EDT 2018" }, { - "details": "Call the customer service", + "description": "Description", "done": true, "id": 6, - "title": "Fix the refrigerator" + "title": "Title", + "updatedDate": "Tue Jul 31 10:25:33 EDT 2018" }, { - "details": "Chat with your friends about last night match", - "done": false, - "id": 7, - "title": "Chat with friends" + "description": "Description", + "done": true, + "id": 33, + "title": "Title", + "updatedDate": "Tue Jul 31 11:14:15 EDT 2018" }, { - "details": "Call the customer service", + "description": "Description", "done": false, - "id": 8, - "title": "Fix the refrigerator" + "id": 41, + "title": "Title", + "updatedDate": "Tue Jul 31 11:27:17 EDT 2018" }, { - "id": 9, - "title": "Buy grocery", - "details": "Go to the market to buy carrots", - "done": false - }, - { - "details": "Chat with your friends about last night match", + "description": "Description", "done": false, - "id": 10, - "title": "Chat with friends" + "id": 73, + "title": "Title", + "updatedDate": "Tue Jul 31 11:27:23 EDT 2018" }, { - "details": "Call the customer service", + "description": "Description", "done": false, - "id": 11, - "title": "Fix the refrigerator" + "id": 17, + "title": "Title", + "updatedDate": "Tue Jul 31 11:35:54 EDT 2018" }, { - "details": "Chat with your friends about last night match", + "description": "dsaDescription", "done": false, - "id": 12, - "title": "Chat with friends" + "id": 110, + "title": "dsaTitle", + "updatedDate": "Tue Jul 31 11:27:43 EDT 2018" }, { - "details": "Call the customer service", + "description": "Description", "done": false, - "id": 13, - "title": "Fix the refrigerator" - }, - { - "details": "Go to the market to buy carrots", - "done": true, - "id": 14, - "title": "Buy grocery" + "id": 37, + "title": "Title", + "updatedDate": "Tue Jul 31 11:36:00 EDT 2018" }, { - "details": "Chat with your friends about last night match", + "description": "Description", "done": false, - "id": 15, - "title": "Chat with friends" + "id": 25, + "title": "Title", + "updatedDate": "Tue Jul 31 11:55:56 EDT 2018" }, { - "details": "Call the customer service", + "description": "Description", "done": false, - "id": 16, - "title": "Fix the refrigerator" + "id": 59, + "title": "Title", + "updatedDate": "Tue Jul 31 11:36:04 EDT 2018" }, { - "details": "", + "description": "Description", "done": false, - "title": "", - "id": 17 + "id": 83, + "title": "Title", + "updatedDate": "Tue Jul 31 11:36:11 EDT 2018" }, { - "details": "Hello World Description", + "description": "Description", "done": false, - "title": "Hello World Title", - "id": 18 + "id": 27, + "title": "Title", + "updatedDate": "Wed Aug 01 10:17:21 EDT 2018" }, { - "details": "Hello 2 Description", + "description": "kidding Description", "done": false, - "title": "Hello 2 Title", - "id": 19 + "id": 57, + "title": "kidding Title", + "updatedDate": "Wed Aug 01 10:17:34 EDT 2018" }, { - "details": "Hello 3 Description", + "description": "Description", "done": false, - "title": "Hello 3 Title", - "id": 20 + "id": 91, + "title": "Title", + "updatedDate": "Wed Aug 01 10:24:17 EDT 2018" }, { - "details": "allo Description", + "description": "Description", "done": false, - "title": "allo Title", - "id": 21 + "id": 125, + "title": "Title", + "updatedDate": "Wed Aug 01 10:24:22 EDT 2018" }, { - "details": "sada Description", + "description": "1Description", "done": false, - "title": "sada Title", - "id": 22 + "id": 109, + "title": "1Title", + "updatedDate": "Thu Aug 02 01:25:51 EDT 2018" }, { - "details": "ddsa Description", + "description": "123 Description", "done": false, - "title": "ddsa Title", - "id": 23 + "id": 35, + "title": "123 Title", + "updatedDate": "Thu Aug 02 01:25:24 EDT 2018" }, { - "details": "dsa Description", - "done": false, - "id": 24, - "title": "dsa Title" + "description": "Hello from the backend", + "done": true, + "id": 1000, + "title": "Hello from the other side", + "updatedDate": "Thu Aug 02 01:25:24 EDT 2018" }, { - "details": "dsa Description", - "done": true, - "id": 25, - "title": "dsa Title" + "description": "11Description", + "done": false, + "id": 81, + "title": "11Title", + "updatedDate": "Thu Aug 02 02:15:38 EDT 2018" }, { - "details": "Ghazy Description", + "description": "Description", "done": false, - "id": 26, - "title": "Title Ghazy" + "id": 43, + "title": "Title", + "updatedDate": "Thu Aug 02 02:18:49 EDT 2018" } ] } \ No newline at end of file diff --git a/readme.md b/readme.md index 9217bbc..58e5ad8 100755 --- a/readme.md +++ b/readme.md @@ -6,8 +6,8 @@ | Retrofit2 | | Dagger 2 | | Data Manager | +| Sync Adapter | | Todo | | :---------------: | -| Use Dagger 2 | -| Use Data Manager | \ No newline at end of file +| Use Job Scheduler | From d987a10a7d8b4ec017326e380ee93b972d389559 Mon Sep 17 00:00:00 2001 From: Ahmed Date: Thu, 2 Aug 2018 08:34:02 +0200 Subject: [PATCH 4/6] remove white spaces from res files --- app/src/main/res/layout/item_todos.xml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/src/main/res/layout/item_todos.xml b/app/src/main/res/layout/item_todos.xml index e0121ee..7bb243f 100755 --- a/app/src/main/res/layout/item_todos.xml +++ b/app/src/main/res/layout/item_todos.xml @@ -7,9 +7,6 @@ android:orientation="horizontal" android:padding="20dp" > - - - - - - - - - - - - \ No newline at end of file From 62f650afe0cb366068d8401eac812b5cb4fd654a Mon Sep 17 00:00:00 2001 From: Ahmed Date: Thu, 2 Aug 2018 09:04:54 +0200 Subject: [PATCH 5/6] Use the same TodosAdapter instance --- .../mvpandroid/ui/todos/TodosAdapter.java | 16 ++++++++++++++++ .../mvpandroid/ui/todos/TodosFragment.java | 13 +++++-------- db.json | 9 ++++++++- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosAdapter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosAdapter.java index 2bb0227..c695b38 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosAdapter.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosAdapter.java @@ -1,6 +1,7 @@ package com.blink22.android.mvpandroid.ui.todos; import android.content.Context; +import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -21,11 +22,26 @@ public class TodosAdapter extends RecyclerView.Adapter { private final OnItemClickListener mListener; private ArrayList mData; + public static TodosAdapter newInstance(Context c, final TodosPresenter todosPresenter) { + return new TodosAdapter(c.getApplicationContext(), new ArrayList(), + new TodosAdapter.OnItemClickListener() { + @Override + public void onClick(Todo item) { + todosPresenter.updateTodo(item); + } + }); + } + TodosAdapter(Context context, ArrayList data, OnItemClickListener listener) { mData = data; mListener = listener; } + void onTodosUpdate(ArrayList todos) { + mData = todos; + notifyDataSetChanged(); + } + @Override @NonNull public TodosVH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java index 68cd295..adeb78d 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosFragment.java @@ -29,6 +29,7 @@ public class TodosFragment extends Fragment implements TodosContract.View { @BindView(R.id.todos_list) RecyclerView mTodos; @BindView(R.id.todos_progress) ProgressBar mProgressBar; private TodosPresenter mTodosPresenter; + private TodosAdapter mTodosAdapter; public static TodosFragment newInstance() { return new TodosFragment(); @@ -38,6 +39,7 @@ public static TodosFragment newInstance() { public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mTodosPresenter = ((TodosActivity) getActivity()).getPresenter(); + mTodosAdapter = TodosAdapter.newInstance(getActivity(), mTodosPresenter); } @Nullable @@ -47,6 +49,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c View v = inflater.inflate(R.layout.todos_fragment, container, false); ButterKnife.bind(this, v); mTodosPresenter.onAttach(this); + mTodos.setAdapter(mTodosAdapter); mTodos.setLayoutManager(new LinearLayoutManager(getActivity())); return v; } @@ -74,13 +77,7 @@ public void onFailure(String appErrorMessage) { @Override public void onGetTodosSuccess(ArrayList todos) { - TodosAdapter adapter = new TodosAdapter(getActivity().getApplicationContext(), todos, - new TodosAdapter.OnItemClickListener() { - @Override - public void onClick(Todo item) { - ((TodosActivity) getActivity()).getPresenter().updateTodo(item); - } - }); - mTodos.setAdapter(adapter); + mTodosAdapter.onTodosUpdate(todos); + mTodos.setAdapter(mTodosAdapter); } } diff --git a/db.json b/db.json index 32fb679..ed22284 100644 --- a/db.json +++ b/db.json @@ -5,7 +5,7 @@ "title": "Hello world", "description": "Hello world", "done": false, - "updatedDate": "Tue Jul 31 14:57:33 GMT 2018" + "updatedDate": "Tue Jul 31 15:57:33 GMT 2018" }, { "description": "Description", @@ -153,6 +153,13 @@ "id": 43, "title": "Title", "updatedDate": "Thu Aug 02 02:18:49 EDT 2018" + }, + { + "description": "Description", + "done": false, + "id": 49, + "title": "Title", + "updatedDate": "Thu Aug 02 02:34:25 EDT 2018" } ] } \ No newline at end of file From 349a6a18ce14ce32189b503755dc3cd8e6b6c3de Mon Sep 17 00:00:00 2001 From: Ahmed Date: Thu, 2 Aug 2018 14:16:36 +0200 Subject: [PATCH 6/6] Use lambda for rxjava subscription and minimize subscription code --- .gitignore | 15 +- .idea/misc.xml | 2 +- app/build.gradle | 21 +- .../mvpandroid/data/AppDataManager.java | 124 ++++-------- .../mvpandroid/data/db/AppDbHelper.java | 24 --- .../android/mvpandroid/data/db/DbHelper.java | 16 +- .../ui/newtodo/NewTodoFragment.java | 2 + .../ui/newtodo/NewTodoPresenter.java | 24 +-- .../mvpandroid/ui/todos/TodosPresenter.java | 49 ++--- build.gradle | 1 + db.json | 188 ++++++++++++------ 11 files changed, 206 insertions(+), 260 deletions(-) diff --git a/.gitignore b/.gitignore index 3c117df..7973735 100644 --- a/.gitignore +++ b/.gitignore @@ -34,13 +34,14 @@ captures/ # IntelliJ *.iml -.idea/workspace.xml -.idea/tasks.xml -.idea/gradle.xml -.idea/assetWizardSettings.xml -.idea/dictionaries -.idea/libraries -.idea/caches +.idea +#.idea/workspace.xml +#.idea/tasks.xml +#.idea/gradle.xml +#.idea/assetWizardSettings.xml +#.idea/dictionaries +#.idea/libraries +#.idea/caches # Keystore files # Uncomment the following line if you do not want to check your keystore files in. diff --git a/.idea/misc.xml b/.idea/misc.xml index eb2d820..eb78749 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -50,7 +50,7 @@ - + diff --git a/app/build.gradle b/app/build.gradle index cb5c7b7..4966fbb 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,42 +19,39 @@ android { buildConfigField "String", "BASE_URL", "\"https://private-986f5d-afghazy.apiary-mock.com/\"" } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:27.1.1' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' - implementation 'com.android.support:design:27.1.1' - implementation 'com.android.support:recyclerview-v7:27.1.1' implementation 'com.android.support:cardview-v7:27.1.1' - implementation 'com.github.bumptech.glide:glide:4.7.1' - provided 'org.glassfish:javax.annotation:10.0-b28' - implementation 'com.google.code.gson:gson:2.8.2' implementation 'com.squareup.retrofit2:retrofit:2.4.0' implementation 'com.squareup.retrofit2:adapter-rxjava:2.4.0' implementation 'com.squareup.retrofit2:converter-gson:2.4.0' implementation 'com.squareup.retrofit2:converter-scalars:2.1.0' - implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' implementation 'io.reactivex.rxjava2:rxjava:2.1.9' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' - implementation 'com.google.dagger:dagger:2.11' annotationProcessor 'com.google.dagger:dagger-compiler:2.11' - implementation 'com.google.dagger:dagger-android:2.11' // If you're using classes in dagger.android - implementation 'com.google.dagger:dagger-android-support:2.11' // if you use the support libraries + implementation 'com.google.dagger:dagger-android:2.11' + // If you're using classes in dagger.android + implementation 'com.google.dagger:dagger-android-support:2.11' + // if you use the support libraries annotationProcessor 'com.google.dagger:dagger-android-processor:2.11' - provided 'javax.annotation:jsr250-api:1.0' - implementation 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java b/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java index fc5c568..73a67fe 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/AppDataManager.java @@ -60,95 +60,23 @@ public void syncData() { mApiHelper.getTodos() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer>() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(final ArrayList apiTodos) { + .subscribe( + apiTodos -> { mDbHelper.getTodos() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer>() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(final ArrayList dbTodos) { - for(Todo dbTodo: dbTodos) { - - boolean mostRecent = false; - boolean found = false; - for(Todo apiTodo: apiTodos) { - if(dbTodo.getId() == apiTodo.getId()) { - found = true; - if (new Date(dbTodo.getUpdatedDate()).compareTo(new Date(apiTodo.getUpdatedDate())) > 0) { - mostRecent = true; - } - } - } - - if(!found) { - mApiHelper.saveTodo(dbTodo).subscribeOn(Schedulers.io()).subscribe(); - - } - else { - if(mostRecent) { - mApiHelper.updateTodo(dbTodo.getId(), dbTodo).subscribeOn(Schedulers.io()).subscribe(); - } - } - } - - for(Todo apiTodo: apiTodos) { - boolean mostRecent = false; - boolean found = false; - for(Todo dbTodo: dbTodos) { - if(dbTodo.getId() == apiTodo.getId()) { - found = true; - if (new Date(apiTodo.getUpdatedDate()).compareTo(new Date(dbTodo.getUpdatedDate())) > 0) { - mostRecent = true; - } - } - } - - if(!found) { - mDbHelper.saveTodo(apiTodo).subscribeOn(Schedulers.io()).subscribe(); - } - else { - if(mostRecent) { - mDbHelper.updateTodo(apiTodo.getId(), apiTodo).subscribeOn(Schedulers.io()).subscribe(); - } - } - } - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - }); - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - }); - + .subscribe( + dbTodos -> { + syncMissingAndUpdatedVersionOfTodos(dbTodos, apiTodos, mApiHelper); + syncMissingAndUpdatedVersionOfTodos(apiTodos, dbTodos, mDbHelper); + }, + throwable -> {}, + () -> {} + + ); + }, + throwable -> {}, + () -> {}); } @Override @@ -160,4 +88,28 @@ public boolean isSyncDone() { public void setSyncDone(boolean syncRequired) { mPrefsHelper.setSyncDone(syncRequired); } + + private void syncMissingAndUpdatedVersionOfTodos(ArrayList sourceArr, ArrayList destinationArr, ApiHelper destination) { + for(Todo srcTodo: sourceArr) { + boolean mostRecent = false; + boolean found = false; + for(Todo destTodo: destinationArr) { + if(srcTodo.getId() == destTodo.getId()) { + found = true; + if (new Date(srcTodo.getUpdatedDate()).compareTo(new Date(destTodo.getUpdatedDate())) > 0) { + mostRecent = true; + } + } + } + + if(!found) { + destination.saveTodo(srcTodo).subscribeOn(Schedulers.io()).subscribe(); + } + else { + if(mostRecent) { + destination.updateTodo(srcTodo.getId(), srcTodo).subscribeOn(Schedulers.io()).subscribe(); + } + } + } + } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java index f58f52f..457b0ca 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/AppDbHelper.java @@ -102,28 +102,4 @@ public void execute(Realm realm) { return observable; } - - @Override - public Observable deleteTodos() { - Observable observable = Observable.create(new ObservableOnSubscribe() { - @Override - public void subscribe(final ObservableEmitter emitter) throws Exception { - try { - final Realm currentRealm = Realm.getDefaultInstance(); - currentRealm.executeTransaction(new Realm.Transaction() { - @Override - public void execute(Realm realm) { - realm.delete(Todo.class); - emitter.onNext(true); - emitter.onComplete(); - } - }); - } catch (Exception e) { - emitter.onError(e); - } - } - }); - - return observable; - } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/data/db/DbHelper.java b/app/src/main/java/com/blink22/android/mvpandroid/data/db/DbHelper.java index 692608d..f2ca8bc 100644 --- a/app/src/main/java/com/blink22/android/mvpandroid/data/db/DbHelper.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/data/db/DbHelper.java @@ -1,23 +1,11 @@ package com.blink22.android.mvpandroid.data.db; -import com.blink22.android.mvpandroid.data.db.model.Todo; - -import java.util.ArrayList; - -import io.reactivex.Observable; +import com.blink22.android.mvpandroid.data.api.ApiHelper; /** * Created by ahmedghazy on 7/30/18. */ -public interface DbHelper { - - Observable saveTodo(Todo todo); - - Observable updateTodo(int id, Todo todo); - - Observable> getTodos(); - - Observable deleteTodos(); +public interface DbHelper extends ApiHelper { } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java index bfdab20..e198f9c 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoFragment.java @@ -5,6 +5,7 @@ import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -33,6 +34,7 @@ public class NewTodoFragment extends Fragment implements NewTodoContract.View { @BindView(R.id.new_todo_submit) Button mSubmit; @OnClick(R.id.new_todo_submit) public void submit() { + Log.i(getClass().getSimpleName(), "Submit"); mNewTodoPresenter.createTodo(); } private NewTodoContract.Presenter mNewTodoPresenter; diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java index 2137d35..b21bde7 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/newtodo/NewTodoPresenter.java @@ -44,23 +44,15 @@ public void createTodo() { .saveTodo(todo) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(new DisposableObserver() { - @Override - public void onNext(Todo todo) { - getView().showToastWithMessage(R.string.create_todo_success); - getView().terminate(); - } + .subscribe( + retTodo -> { + getView().showToastWithMessage(R.string.create_todo_success); + getView().terminate(); + }, + throwable -> {}, + () -> {} + )); - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - })); } } } diff --git a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java index 06d47eb..ec9493a 100755 --- a/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java +++ b/app/src/main/java/com/blink22/android/mvpandroid/ui/todos/TodosPresenter.java @@ -12,6 +12,7 @@ import com.blink22.android.mvpandroid.ui.base.BasePresenter; import java.util.ArrayList; +import java.util.Date; import java.util.Observable; import java.util.Observer; @@ -63,23 +64,14 @@ public void getTodos() { .getTodos() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(new DisposableObserver>() { - @Override - public void onNext(ArrayList todos) { - getView().onGetTodosSuccess(todos); - getView().removeWait(); - } - - @Override - public void onError(Throwable e) { - getView().onFailure(e.getMessage()); - } - - @Override - public void onComplete() { - - } - }) + .subscribe( + todos -> { + getView().removeWait(); + getView().onGetTodosSuccess(todos); + }, + throwable -> getView().onFailure(throwable.getLocalizedMessage()), + () -> {} + ) ); } } @@ -87,27 +79,16 @@ public void onComplete() { @Override public void updateTodo(Todo todo) { todo.setDone(!todo.isDone()); + todo.setUpdatedDate(new Date().toString()); getCompositeDisposable().add( getDataManager() .updateTodo(todo.getId(), todo) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(new DisposableObserver( - ) { - @Override - public void onNext(Todo todo) { - - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - }) + .subscribe( + retTodo -> {}, + throwable -> {}, + () -> {} + ) ); } } diff --git a/build.gradle b/build.gradle index 6a4c9bc..32b2f9d 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.0.1' classpath 'io.realm:realm-gradle-plugin:5.4.0' + classpath 'me.tatarka:gradle-retrolambda:3.5.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/db.json b/db.json index ed22284..f1d64a3 100644 --- a/db.json +++ b/db.json @@ -1,10 +1,17 @@ { "todos": [ { + "description": "Description", + "done": true, + "id": 6, + "title": "Title", + "updatedDate": "Tue Jul 31 10:27:35 EDT 2018" + }, + { + "description": "Hello world", + "done": true, "id": 100, "title": "Hello world", - "description": "Hello world", - "done": false, "updatedDate": "Tue Jul 31 15:57:33 GMT 2018" }, { @@ -16,150 +23,199 @@ }, { "description": "Description", - "done": false, - "id": 13, + "done": true, + "id": 33, "title": "Title", - "updatedDate": "Tue Jul 31 10:25:39 EDT 2018" + "updatedDate": "Tue Jul 31 11:14:15 EDT 2018" }, { "description": "Description", "done": true, - "id": 6, + "id": 13, "title": "Title", - "updatedDate": "Tue Jul 31 10:25:33 EDT 2018" + "updatedDate": "Tue Jul 31 10:25:39 EDT 2018" }, { - "description": "Description", + "description": "dsaDescription", "done": true, - "id": 33, - "title": "Title", - "updatedDate": "Tue Jul 31 11:14:15 EDT 2018" + "id": 110, + "title": "dsaTitle", + "updatedDate": "Tue Jul 31 11:27:43 EDT 2018" }, { "description": "Description", - "done": false, + "done": true, "id": 41, "title": "Title", "updatedDate": "Tue Jul 31 11:27:17 EDT 2018" }, { "description": "Description", - "done": false, - "id": 73, + "done": true, + "id": 83, "title": "Title", - "updatedDate": "Tue Jul 31 11:27:23 EDT 2018" + "updatedDate": "Tue Jul 31 11:36:11 EDT 2018" }, { "description": "Description", - "done": false, + "done": true, "id": 17, "title": "Title", "updatedDate": "Tue Jul 31 11:35:54 EDT 2018" }, - { - "description": "dsaDescription", - "done": false, - "id": 110, - "title": "dsaTitle", - "updatedDate": "Tue Jul 31 11:27:43 EDT 2018" - }, { "description": "Description", - "done": false, - "id": 37, + "done": true, + "id": 27, "title": "Title", - "updatedDate": "Tue Jul 31 11:36:00 EDT 2018" + "updatedDate": "Wed Aug 01 10:17:21 EDT 2018" }, { "description": "Description", - "done": false, - "id": 25, + "done": true, + "id": 91, "title": "Title", - "updatedDate": "Tue Jul 31 11:55:56 EDT 2018" + "updatedDate": "Wed Aug 01 10:24:17 EDT 2018" }, { "description": "Description", - "done": false, - "id": 59, + "done": true, + "id": 73, "title": "Title", - "updatedDate": "Tue Jul 31 11:36:04 EDT 2018" + "updatedDate": "Tue Jul 31 11:27:23 EDT 2018" }, { "description": "Description", - "done": false, - "id": 83, + "done": true, + "id": 125, "title": "Title", - "updatedDate": "Tue Jul 31 11:36:11 EDT 2018" + "updatedDate": "Wed Aug 01 10:24:22 EDT 2018" }, { "description": "Description", - "done": false, - "id": 27, + "done": true, + "id": 37, "title": "Title", - "updatedDate": "Wed Aug 01 10:17:21 EDT 2018" + "updatedDate": "Tue Jul 31 11:36:00 EDT 2018" }, { "description": "kidding Description", - "done": false, + "done": true, "id": 57, "title": "kidding Title", "updatedDate": "Wed Aug 01 10:17:34 EDT 2018" }, + { + "description": "Hello from the backend", + "done": true, + "id": 1000, + "title": "Hello from the other side", + "updatedDate": "Thu Aug 02 01:25:24 EDT 2018" + }, { "description": "Description", - "done": false, - "id": 91, + "done": true, + "id": 59, "title": "Title", - "updatedDate": "Wed Aug 01 10:24:17 EDT 2018" + "updatedDate": "Tue Jul 31 11:36:04 EDT 2018" + }, + { + "description": "11Description", + "done": true, + "id": 81, + "title": "11Title", + "updatedDate": "Thu Aug 02 02:15:38 EDT 2018" }, { "description": "Description", - "done": false, - "id": 125, + "done": true, + "id": 25, "title": "Title", - "updatedDate": "Wed Aug 01 10:24:22 EDT 2018" + "updatedDate": "Tue Jul 31 11:55:56 EDT 2018" }, { - "description": "1Description", - "done": false, - "id": 109, - "title": "1Title", - "updatedDate": "Thu Aug 02 01:25:51 EDT 2018" + "description": "Description", + "done": true, + "id": 43, + "title": "Title", + "updatedDate": "Thu Aug 02 02:18:49 EDT 2018" + }, + { + "description": "ggDescription", + "done": true, + "id": 95, + "title": "ggTitle", + "updatedDate": "Thu Aug 02 07:53:27 EDT 2018" }, { "description": "123 Description", - "done": false, + "done": true, "id": 35, "title": "123 Title", "updatedDate": "Thu Aug 02 01:25:24 EDT 2018" }, { - "description": "Hello from the backend", + "description": "Description", "done": true, - "id": 1000, - "title": "Hello from the other side", - "updatedDate": "Thu Aug 02 01:25:24 EDT 2018" - }, - { - "description": "11Description", - "done": false, - "id": 81, - "title": "11Title", - "updatedDate": "Thu Aug 02 02:15:38 EDT 2018" + "id": 58, + "title": "Title", + "updatedDate": "Thu Aug 02 08:01:09 EDT 2018" }, { "description": "Description", - "done": false, - "id": 43, + "done": true, + "id": 118, "title": "Title", - "updatedDate": "Thu Aug 02 02:18:49 EDT 2018" + "updatedDate": "Thu Aug 02 08:01:17 EDT 2018" }, { "description": "Description", - "done": false, + "done": true, "id": 49, "title": "Title", "updatedDate": "Thu Aug 02 02:34:25 EDT 2018" + }, + { + "description": "Description dsad", + "done": true, + "id": 180, + "title": "Title dsadsa", + "updatedDate": "Thu Aug 02 08:01:23 EDT 2018" + }, + { + "description": "ggDescription", + "done": true, + "id": 99, + "title": "ggTitle", + "updatedDate": "Thu Aug 02 07:53:42 EDT 2018" + }, + { + "description": "1Description", + "done": true, + "id": 109, + "title": "1Title", + "updatedDate": "Thu Aug 02 01:25:51 EDT 2018" + }, + { + "description": "ggDescription", + "done": true, + "id": 97, + "title": "ggTitle", + "updatedDate": "Thu Aug 02 07:53:29 EDT 2018" + }, + { + "description": "Description", + "done": true, + "id": 55, + "title": "Title", + "updatedDate": "Thu Aug 02 07:57:42 EDT 2018" + }, + { + "description": "Description", + "done": true, + "id": 53, + "title": "Title", + "updatedDate": "Thu Aug 02 07:56:06 EDT 2018" } ] } \ No newline at end of file