diff --git a/Task3. TaskManager/TaskManager/.idea/dictionaries/JeMinay.xml b/Task3. TaskManager/TaskManager/.idea/dictionaries/JeMinay.xml index f14db48..26f13c9 100644 --- a/Task3. TaskManager/TaskManager/.idea/dictionaries/JeMinay.xml +++ b/Task3. TaskManager/TaskManager/.idea/dictionaries/JeMinay.xml @@ -2,7 +2,9 @@ itemlist + resultable showable + thenable unsubscribe diff --git a/Task3. TaskManager/TaskManager/.idea/inspectionProfiles/Project_Default.xml b/Task3. TaskManager/TaskManager/.idea/inspectionProfiles/Project_Default.xml index 8f908f4..5878c7a 100644 --- a/Task3. TaskManager/TaskManager/.idea/inspectionProfiles/Project_Default.xml +++ b/Task3. TaskManager/TaskManager/.idea/inspectionProfiles/Project_Default.xml @@ -1,11 +1,13 @@ - - - - - - - - - - diff --git a/Task3. TaskManager/TaskManager/app/build.gradle b/Task3. TaskManager/TaskManager/app/build.gradle index db2caf6..d610082 100644 --- a/Task3. TaskManager/TaskManager/app/build.gradle +++ b/Task3. TaskManager/TaskManager/app/build.gradle @@ -46,6 +46,7 @@ dependencies { compile 'com.github.javiersantos:BottomDialogs:1.2.1' compile 'com.daasuu:animateHorizontalProgressBar:0.2.4' compile 'com.github.florent37:singledateandtimepicker:1.1.0' + compile 'com.loopj.android:android-async-http:1.4.9' compile 'com.android.support:appcompat-v7:25.3.1' compile 'com.android.support:cardview-v7:25.3.1' compile 'com.android.support.constraint:constraint-layout:1.0.2' diff --git a/Task3. TaskManager/TaskManager/app/src/main/AndroidManifest.xml b/Task3. TaskManager/TaskManager/app/src/main/AndroidManifest.xml index 6ff8e26..4217f88 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/AndroidManifest.xml +++ b/Task3. TaskManager/TaskManager/app/src/main/AndroidManifest.xml @@ -3,6 +3,8 @@ package="ru.urfu.taskmanager"> + + @@ -15,10 +17,9 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> + @@ -26,10 +27,15 @@ + + + \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/Application.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/Application.java index 161b45a..1439173 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/Application.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/Application.java @@ -1,12 +1,16 @@ package ru.urfu.taskmanager; +import android.content.BroadcastReceiver; + import ru.urfu.taskmanager.color_picker.recent.RecentColorsStorage; import ru.urfu.taskmanager.task_manager.main.filter.FiltersStorage; -import ru.urfu.taskmanager.utils.db.DbTasks; +import ru.urfu.taskmanager.data.db.DbTasks; import ru.urfu.taskmanager.utils.tools.SizeManager; public class Application extends android.app.Application { + private BroadcastReceiver apiSyncReceiver; + @Override public void onCreate() { super.onCreate(); diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/auth/LoginActivity.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/auth/LoginActivity.java new file mode 100644 index 0000000..7716ff3 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/auth/LoginActivity.java @@ -0,0 +1,44 @@ +package ru.urfu.taskmanager.auth; + +import android.content.Intent; +import android.support.v7.app.AppCompatActivity; +import android.widget.EditText; + +import org.androidannotations.annotations.AfterViews; +import org.androidannotations.annotations.Click; +import org.androidannotations.annotations.EActivity; +import org.androidannotations.annotations.ViewById; + +import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.auth.models.User; +import ru.urfu.taskmanager.task_manager.main.view.TaskManagerActivity_; + +@EActivity(R.layout.activity_login) +public class LoginActivity extends AppCompatActivity +{ + @ViewById(R.id.loginEditText) + EditText mLoginEditText; + + @AfterViews + public void init() { + if (User.getActiveUser() != null) { + afterLogin(); + } + } + + @Click(R.id.loginButton) + public void doLogin() { + String login = mLoginEditText.getText().toString(); + if (!login.isEmpty()) { + User.doLogin(getApplicationContext(), login); + afterLogin(); + } + } + + private void afterLogin() { + Intent intent = new Intent(this, TaskManagerActivity_.class); + startActivity(intent); + + finish(); + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/auth/models/User.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/auth/models/User.java new file mode 100644 index 0000000..e3f0eee --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/auth/models/User.java @@ -0,0 +1,60 @@ +package ru.urfu.taskmanager.auth.models; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.provider.Settings; + +import ru.urfu.taskmanager.data.network.APIServiceExecutor; +import ru.urfu.taskmanager.data.network.APIService; + +public class User +{ + private static User activeUser; + + private int mId; + private String mLogin; + private APIService mApiService; + private APIServiceExecutor mAPIServiceExecutor; + private String deviceIdentifier; + + + private User(Context context, String mLogin) { + this.mId = Math.abs(mLogin.hashCode()); + this.mLogin = mLogin; + this.deviceIdentifier = initDeviceId(context); + this.mAPIServiceExecutor = new APIServiceExecutor(context, mApiService = new APIService(this)); + } + + public int getUserId() { + return mId; + } + + public String getDeviceIdentifier() { + return deviceIdentifier; + } + + public String getLogin() { + return mLogin; + } + + public APIServiceExecutor getExecutor() { + return mAPIServiceExecutor; + } + + public APIService getService() { + return mApiService; + } + + @SuppressLint("HardwareIds") + private static String initDeviceId(Context context) { + return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); + } + + public static void doLogin(Context context, String login) { + activeUser = new User(context, login); + } + + public static User getActiveUser() { + return activeUser; + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/BackupManager.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/BackupManager.java similarity index 92% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/BackupManager.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/BackupManager.java index c029b6f..5ffb6c7 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/BackupManager.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/BackupManager.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.task_manager.main.tools; +package ru.urfu.taskmanager.data.backup; import android.os.Build; import android.os.Handler; @@ -22,8 +22,7 @@ import java.util.ArrayList; import java.util.List; -import ru.urfu.taskmanager.utils.db.async.ExecuteController; -import ru.urfu.taskmanager.utils.tools.JSONFactory; +import ru.urfu.taskmanager.data.db.async.ExecuteController; public class BackupManager extends HandlerThread { @@ -52,7 +51,7 @@ public void exportTo(DataProvider provider) { try { outputStream = new FileOutputStream(file); BufferedWriter bufferedWriter; - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); } else { @@ -84,7 +83,7 @@ public void importFrom(InputStream inputStream, Class _class, ExecuteCont .create(); try { InputStreamReader streamReader; - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { streamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); } else { diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/DataExportController.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/DataExportController.java similarity index 96% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/DataExportController.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/DataExportController.java index 3af2a68..cd1fcc5 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/DataExportController.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/DataExportController.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.task_manager.main.tools; +package ru.urfu.taskmanager.data.backup; import android.app.NotificationManager; import android.content.Context; @@ -7,7 +7,7 @@ import java.util.List; import ru.urfu.taskmanager.R; -import ru.urfu.taskmanager.utils.db.async.ExecuteControllerAdapter; +import ru.urfu.taskmanager.data.db.async.ExecuteControllerAdapter; import ru.urfu.taskmanager.utils.interfaces.Progressive; public class DataExportController extends ExecuteControllerAdapter> diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/DataImportController.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/DataImportController.java similarity index 94% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/DataImportController.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/DataImportController.java index 60f2194..161bdad 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/DataImportController.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/DataImportController.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.task_manager.main.tools; +package ru.urfu.taskmanager.data.backup; import android.app.NotificationManager; import android.content.Context; @@ -7,9 +7,9 @@ import java.util.List; import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.data.db.async.DbAsyncExecutor; +import ru.urfu.taskmanager.data.db.async.ExecuteControllerAdapter; import ru.urfu.taskmanager.task_manager.main.view.TaskManager; -import ru.urfu.taskmanager.utils.db.async.DbAsyncExecutor; -import ru.urfu.taskmanager.utils.db.async.ExecuteControllerAdapter; import ru.urfu.taskmanager.utils.interfaces.Callback; public class DataImportController extends ExecuteControllerAdapter> diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/TasksGenerator.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/TasksGenerator.java similarity index 93% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/TasksGenerator.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/TasksGenerator.java index 2342564..2434be9 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/tools/TasksGenerator.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/backup/TasksGenerator.java @@ -1,19 +1,17 @@ -package ru.urfu.taskmanager.task_manager.main.tools; +package ru.urfu.taskmanager.data.backup; import android.app.NotificationManager; import android.content.Context; import android.graphics.Color; import android.support.v4.app.NotificationCompat; -import org.androidannotations.annotations.res.StringRes; - import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.data.db.DbTasks; +import ru.urfu.taskmanager.data.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.async.AsyncExecutor; +import ru.urfu.taskmanager.data.db.async.ExecuteControllerAdapter; import ru.urfu.taskmanager.task_manager.main.presenter.TaskManagerPresenter; import ru.urfu.taskmanager.task_manager.models.TaskEntry; -import ru.urfu.taskmanager.utils.db.async.AsyncExecutor; -import ru.urfu.taskmanager.utils.db.DbTasks; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; -import ru.urfu.taskmanager.utils.db.async.ExecuteControllerAdapter; import ru.urfu.taskmanager.utils.interfaces.Progressive; public class TasksGenerator diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbFilter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbFilter.java similarity index 70% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbFilter.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbFilter.java index 9f81a43..e042d17 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbFilter.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbFilter.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.utils.db; +package ru.urfu.taskmanager.data.db; public interface DbFilter { @@ -13,4 +13,8 @@ public interface DbFilter String getHaving(); String getOrderBy(); + + boolean isOrdered(); + + int getType(); } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbTasks.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbTasks.java similarity index 77% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbTasks.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbTasks.java index 86649e3..1632e4e 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbTasks.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbTasks.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.utils.db; +package ru.urfu.taskmanager.data.db; import android.content.ContentValues; import android.content.Context; @@ -8,12 +8,11 @@ import java.util.ArrayList; import java.util.List; +import ru.urfu.taskmanager.auth.models.User; import ru.urfu.taskmanager.task_manager.models.TaskEntry; -import ru.urfu.taskmanager.utils.db.async.DbAsyncExecutor; +import ru.urfu.taskmanager.data.db.async.DbAsyncExecutor; import ru.urfu.taskmanager.utils.interfaces.Callback; -import static ru.urfu.taskmanager.utils.db.DbTasksFilter.COMPLETED_TASK; - public class DbTasks implements SimpleDatabase { private static DbTasks sInstance; @@ -41,18 +40,20 @@ public List getAllEntries() { } @Override - public void insertEntry(TaskEntry entry) { - mDatabase.insert(DbTasksHelper.TABLE_NAME, null, contentValuesFrom(entry)); + public long insertEntry(TaskEntry entry) { + long id = mDatabase.insert(DbTasksHelper.TABLE_NAME, null, contentValuesFrom(entry)); + updateEntry(getEntryById((int) id).setOrder((int) id)); + return id; } @Override public void removeEntryById(int id) { - mDatabase.delete(DbTasksHelper.TABLE_NAME, DbTasksHelper.ID + " = " + id, null); + mDatabase.delete(DbTasksHelper.TABLE_NAME, DbTasksHelper.ID + "=" + id, null); } @Override public TaskEntry updateEntry(TaskEntry entry) { - mDatabase.update(DbTasksHelper.TABLE_NAME, contentValuesFrom(entry), DbTasksHelper.ID + " = " + entry.getId(), null); + mDatabase.update(DbTasksHelper.TABLE_NAME, contentValuesFrom(entry), DbTasksHelper.ID + "=" + entry.getId(), null); return getEntryById(entry.getId()); } @@ -82,6 +83,18 @@ public TaskEntry getEntryById(int id) { return getCurrentEntryFromCursor(cursor); } + public TaskEntry getEntryByEntryId(int entryId) { + Cursor cursor = mDatabase.rawQuery("SELECT * FROM " + + DbTasksHelper.TABLE_NAME + " WHERE " + + DbTasksHelper.ENTRY_ID + "=" + entryId + " AND " + + DbTasksHelper.USER_ID + "=" + User.getActiveUser().getUserId(), null); + + if (cursor.getCount() == 0) return null; + + cursor.moveToFirst(); + return getCurrentEntryFromCursor(cursor); + } + @Override public void replaceAll(List entries) { mDatabase.delete(DbTasksHelper.TABLE_NAME, null, null); @@ -94,25 +107,27 @@ public void replaceAll(List entries) { public TaskEntry getCurrentEntryFromCursor(Cursor cursor) { int id = cursor.getColumnIndex(DbTasksHelper.ID); + int order = cursor.getColumnIndex(DbTasksHelper.ORDER); int title = cursor.getColumnIndex(DbTasksHelper.TITLE); + int entry_id = cursor.getColumnIndex(DbTasksHelper.ENTRY_ID); + int image_url = cursor.getColumnIndex(DbTasksHelper.IMAGE_URL); int timetolive = cursor.getColumnIndex(DbTasksHelper.TTL); int time_edited = cursor.getColumnIndex(DbTasksHelper.TIME_EDITED); int time_created = cursor.getColumnIndex(DbTasksHelper.TIME_CREATED); int description = cursor.getColumnIndex(DbTasksHelper.DESCRIPTION); - int isCompleted = cursor.getColumnIndex(DbTasksHelper.COMPLETED); int decorate_color = cursor.getColumnIndex(DbTasksHelper.DECORATE_COLOR); - int image_url = cursor.getColumnIndex(DbTasksHelper.IMAGE_URL); return new TaskEntry(cursor.getInt(id)) + .setId(cursor.getInt(id)) + .setOrder(cursor.getInt(order)) + .setEntryId(cursor.getInt(entry_id)) .setTitle(cursor.getString(title)) .setDescription(cursor.getString(description)) - .setTtl(Long.valueOf(cursor.getString(timetolive))) .setCreated(Long.valueOf(cursor.getString(time_created))) .setEdited(Long.valueOf(cursor.getString(time_edited))) .setTtl(Long.valueOf(cursor.getString(timetolive))) .setColor(cursor.getInt(decorate_color)) - .setImageUrl(cursor.getString(image_url)) - .setCompleted(cursor.getInt(isCompleted) == COMPLETED_TASK); + .setImageUrl(cursor.getString(image_url)); } public Cursor getCursor(DbFilter filter) { @@ -133,22 +148,35 @@ public DbAsyncExecutor getAsyncExecutor() { private ContentValues contentValuesFrom(TaskEntry entry) { ContentValues values = new ContentValues(); + + if (entry.getEntryId() != null) + values.put(DbTasksHelper.ENTRY_ID, entry.getEntryId()); + if (entry.getTtl() != null) values.put(DbTasksHelper.TTL, entry.getTtlTimestamp()); + if (entry.getTitle() != null) values.put(DbTasksHelper.TITLE, entry.getTitle()); + if (entry.getDescription() != null) values.put(DbTasksHelper.DESCRIPTION, entry.getDescription()); + if (entry.getEdited() != null) values.put(DbTasksHelper.TIME_EDITED, entry.getEditedTimestamp()); + if (entry.getCreated() != null) values.put(DbTasksHelper.TIME_CREATED, entry.getCreatedTimestamp()); + if (entry.getColor() != null) values.put(DbTasksHelper.DECORATE_COLOR, entry.getColorInt()); + if (entry.getImageUrl() != null) values.put(DbTasksHelper.IMAGE_URL, entry.getImageUrl()); - values.put(DbTasksHelper.COMPLETED, entry.isCompleted()); + if (entry.getOrder() != null) + values.put(DbTasksHelper.ORDER, entry.getOrder()); + + values.put(DbTasksHelper.USER_ID, User.getActiveUser().getUserId()); return values; } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbTasksFilter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbTasksFilter.java similarity index 86% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbTasksFilter.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbTasksFilter.java index fa221fa..1f683b5 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbTasksFilter.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbTasksFilter.java @@ -1,8 +1,10 @@ -package ru.urfu.taskmanager.utils.db; +package ru.urfu.taskmanager.data.db; import java.util.ArrayList; import java.util.List; +import ru.urfu.taskmanager.auth.models.User; + import static android.text.format.DateUtils.DAY_IN_MILLIS; public class DbTasksFilter implements DbFilter @@ -45,6 +47,8 @@ public String[] getColumns() { } public String getWhereClause() { + mWhereClause.add(DbTasksHelper.USER_ID + "=" + User.getActiveUser().getUserId()); + StringBuilder builder = new StringBuilder(); for (int i = 0; i < mWhereClause.size(); i++) { builder.append(mWhereClause.get(i)); @@ -76,6 +80,10 @@ public String getOrderBy() { return mOrderBy + " " + mOrientation; } + public boolean isOrdered() { + return mOrderBy.equals(DbTasksHelper.ORDER); + } + public int getType() { return mType; } @@ -102,9 +110,18 @@ public boolean isDefault() { public Builder setType(int type) { mFilter.mType = type; - if (type != ALL_TASK) { - mFilter.mWhereClause.add(DbTasksHelper.COMPLETED + "=" + String.valueOf(type)); + + switch (type) { + case ALL_TASK: + break; + case ACTIVE_TASK: + mFilter.mWhereClause.add(DbTasksHelper.TIME_EDITED + "!=" + DbTasksHelper.TTL); + break; + case COMPLETED_TASK: + mFilter.mWhereClause.add(DbTasksHelper.TIME_EDITED + "=" + DbTasksHelper.TTL); + break; } + return this; } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbTasksHelper.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbTasksHelper.java similarity index 77% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbTasksHelper.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbTasksHelper.java index 5c0b16c..967f4e2 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/DbTasksHelper.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/DbTasksHelper.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.utils.db; +package ru.urfu.taskmanager.data.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; @@ -11,13 +11,15 @@ public class DbTasksHelper extends SQLiteOpenHelper public static final int DATABASE_VERSION = 1; public static final String ID = "_id"; + public static final String ORDER = "_order"; + public static final String USER_ID = "_user_id"; + public static final String ENTRY_ID = "_entry_id"; public static final String TITLE = "_title"; public static final String DESCRIPTION = "_description"; public static final String TTL = "_timetolive"; public static final String TIME_CREATED = "_time_created"; public static final String TIME_EDITED = "_time_edited"; public static final String DECORATE_COLOR = "_decorate_color"; - public static final String COMPLETED = "_completed"; public static final String IMAGE_URL = "_img_url"; public DbTasksHelper(Context context) { @@ -27,15 +29,17 @@ public DbTasksHelper(Context context) { @Override public void onCreate(SQLiteDatabase database) { database.execSQL("create table " + TABLE_NAME + "(" + - ID + " integer primary key," + + ID + " integer primary key autoincrement," + + ORDER + " integer," + + USER_ID + " integer," + + ENTRY_ID + " integer," + TITLE + " text," + DESCRIPTION + " text," + TTL + " text," + TIME_CREATED + " text," + TIME_EDITED + " text," + IMAGE_URL + " text," + - DECORATE_COLOR + " integer," + - COMPLETED + " integer" + ")" + DECORATE_COLOR + " integer" + ")" ); } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/SimpleDatabase.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/SimpleDatabase.java similarity index 78% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/SimpleDatabase.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/SimpleDatabase.java index bf027e6..281d0c0 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/SimpleDatabase.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/SimpleDatabase.java @@ -1,10 +1,9 @@ -package ru.urfu.taskmanager.utils.db; +package ru.urfu.taskmanager.data.db; import android.database.Cursor; import java.util.List; -import ru.urfu.taskmanager.task_manager.models.TaskEntry; import ru.urfu.taskmanager.utils.interfaces.Callback; public interface SimpleDatabase @@ -13,7 +12,7 @@ public interface SimpleDatabase T getEntryById(int id); - void insertEntry(T entry); + long insertEntry(T entry); void removeEntryById(int id); diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/AsyncExecutor.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/AsyncExecutor.java similarity index 80% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/AsyncExecutor.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/AsyncExecutor.java index fc33f2a..abe19a2 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/AsyncExecutor.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/AsyncExecutor.java @@ -1,11 +1,11 @@ -package ru.urfu.taskmanager.utils.db.async; +package ru.urfu.taskmanager.data.db.async; import android.database.Cursor; import android.support.annotation.NonNull; import java.util.List; -import ru.urfu.taskmanager.utils.db.DbFilter; +import ru.urfu.taskmanager.data.db.DbFilter; public interface AsyncExecutor @@ -16,11 +16,11 @@ public interface AsyncExecutor void insertEntry(@NonNull T entry); - void insertEntry(@NonNull T entry, @NonNull ExecuteController controller); + void insertEntry(@NonNull T entry, @NonNull ExecuteController controller); void removeEntryById(int id); - void removeEntryById(int id, @NonNull ExecuteController controller); + void removeEntryById(int id, @NonNull ExecuteController controller); void updateEntry(@NonNull T entry); diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/DbAsyncExecutor.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/DbAsyncExecutor.java similarity index 90% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/DbAsyncExecutor.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/DbAsyncExecutor.java index b7a0a15..db1be05 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/DbAsyncExecutor.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/DbAsyncExecutor.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.utils.db.async; +package ru.urfu.taskmanager.data.db.async; import android.database.Cursor; import android.os.AsyncTask; @@ -9,9 +9,9 @@ import java.util.ArrayList; import java.util.List; -import ru.urfu.taskmanager.utils.db.DbFilter; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; -import ru.urfu.taskmanager.utils.db.SimpleDatabase; +import ru.urfu.taskmanager.data.db.DbFilter; +import ru.urfu.taskmanager.data.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.SimpleDatabase; public class DbAsyncExecutor extends HandlerThread implements AsyncExecutor { @@ -93,11 +93,11 @@ public void insertEntry(@NonNull T entry) { } @Override - public void insertEntry(@NonNull T entry, @NonNull ExecuteController controller) { + public void insertEntry(@NonNull T entry, @NonNull ExecuteController controller) { mWorkerHandler.post(() -> { controller.onStart(); - mDatabase.insertEntry(entry); - controller.onFinish(null); + T inserted = mDatabase.getEntryById((int) mDatabase.insertEntry(entry)); + controller.onFinish(inserted); }); } @@ -107,11 +107,12 @@ public void removeEntryById(int id) { } @Override - public void removeEntryById(int id, @NonNull ExecuteController controller) { + public void removeEntryById(int id, @NonNull ExecuteController controller) { mWorkerHandler.post(() -> { controller.onStart(); + T entry = mDatabase.getEntryById(id); mDatabase.removeEntryById(id); - controller.onFinish(null); + controller.onFinish(entry); }); } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/ExecuteController.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/ExecuteController.java similarity index 80% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/ExecuteController.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/ExecuteController.java index 6ea3931..bb35980 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/ExecuteController.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/ExecuteController.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.utils.db.async; +package ru.urfu.taskmanager.data.db.async; import android.support.annotation.Nullable; diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/ExecuteControllerAdapter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/ExecuteControllerAdapter.java similarity index 95% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/ExecuteControllerAdapter.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/ExecuteControllerAdapter.java index 8affa42..e500404 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/db/async/ExecuteControllerAdapter.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/db/async/ExecuteControllerAdapter.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.utils.db.async; +package ru.urfu.taskmanager.data.db.async; import android.app.NotificationManager; import android.support.annotation.Nullable; diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APICallback.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APICallback.java new file mode 100644 index 0000000..563af96 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APICallback.java @@ -0,0 +1,14 @@ +package ru.urfu.taskmanager.data.network; + +public abstract class APICallback implements APICallbackInterface +{ + @Override + public void onResponse(APIResponse response) { + // Stub! + } + + @Override + public void onFailure(Throwable t) { + t.printStackTrace(); + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APICallbackInterface.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APICallbackInterface.java new file mode 100644 index 0000000..2e3d1b2 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APICallbackInterface.java @@ -0,0 +1,8 @@ +package ru.urfu.taskmanager.data.network; + +public interface APICallbackInterface +{ + void onResponse(APIResponse response); + + void onFailure(Throwable t); +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIRequest.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIRequest.java new file mode 100644 index 0000000..e451e91 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIRequest.java @@ -0,0 +1,115 @@ +package ru.urfu.taskmanager.data.network; + +import android.accounts.NetworkErrorException; +import android.net.ParseException; + +import com.google.gson.reflect.TypeToken; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Type; + +import cz.msebera.android.httpclient.client.methods.CloseableHttpResponse; +import cz.msebera.android.httpclient.client.methods.HttpUriRequest; +import cz.msebera.android.httpclient.impl.client.CloseableHttpClient; +import cz.msebera.android.httpclient.impl.client.HttpClientBuilder; +import ru.urfu.taskmanager.utils.tools.JSONFactory; + +public class APIRequest +{ + private HttpUriRequest request; + private Type parseType; + + public APIRequest(HttpUriRequest request) { + this.request = request; + } + + public APIRequest(HttpUriRequest request, Type type) { + this.request = request; + this.parseType = type; + } + + public void send() { + send(new APICallbackInterface() + { + @Override + public void onResponse(APIResponse response) { + } + + @Override + public void onFailure(Throwable t) { + t.printStackTrace(); + } + }); + } + + public void send(APICallbackInterface cb) + { + new Thread(() -> + { + CloseableHttpClient client = null; + CloseableHttpResponse response = null; + + try + { + client = HttpClientBuilder.create().build(); + response = client.execute(request); + + APIResponse apiResponse = null; + + if(response.getEntity() != null) + { + BufferedReader reader = new BufferedReader( + new InputStreamReader(response.getEntity().getContent())); + + StringBuilder stringBuilder = new StringBuilder(); + String line; + + while ((line = reader.readLine()) != null) + { + stringBuilder.append(line); + } + + if (parseType != null) { + apiResponse = JSONFactory.fromJson(stringBuilder.toString(), + TypeToken.getParameterized(APIResponse.class, parseType).getType()); + } else { + apiResponse = JSONFactory.fromJson(stringBuilder.toString(), + new TypeToken>(){}.getType()); + } + + reader.close(); + } + + if (apiResponse != null) { + if (apiResponse.getStatus().equals(APIResponse.STATUS_OK)) { + cb.onResponse(apiResponse); + } else { + cb.onFailure(new NetworkErrorException("The server response is different than expected.")); + } + } else { + cb.onFailure(new NetworkErrorException("The server did not receive a reply.")); + } + } + catch (IOException | ParseException e) + { + cb.onFailure(e); + e.printStackTrace(); + } + finally + { + try + { + if (response != null) response.close(); + if (client != null) client.close(); + } + catch (IOException e) + { + cb.onFailure(e); + e.printStackTrace(); + } + } + }).start(); + } +} \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIResponse.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIResponse.java new file mode 100644 index 0000000..29c5b60 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIResponse.java @@ -0,0 +1,32 @@ +package ru.urfu.taskmanager.data.network; + +import com.google.gson.annotations.SerializedName; + +public class APIResponse +{ + public static final String STATUS_OK = "ok"; + + public static final String PARSE_ERROR = "parse_error"; + public static final String QUERY_FAILED = "query_failed"; + public static final String NOT_FOUND = "not_found"; + + private transient int statusCode; + + private String status; + private String error; + + @SerializedName("data") + private T body; + + public T getBody() { + return body; + } + + public String getStatus() { + return status; + } + + public boolean isError() { + return error != null; + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIService.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIService.java new file mode 100644 index 0000000..32ddb1f --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIService.java @@ -0,0 +1,69 @@ +package ru.urfu.taskmanager.data.network; + +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.sql.Types; +import java.util.ArrayList; +import java.util.Collection; + +import cz.msebera.android.httpclient.client.methods.HttpDelete; +import cz.msebera.android.httpclient.client.methods.HttpGet; +import cz.msebera.android.httpclient.client.methods.HttpPost; +import cz.msebera.android.httpclient.entity.StringEntity; +import ru.urfu.taskmanager.auth.models.User; +import ru.urfu.taskmanager.task_manager.models.TaskEntry; +import ru.urfu.taskmanager.utils.tools.JSONFactory; + +public class APIService +{ + private static final String SERVER_BASE_URL = "https://notesbackend-yufimtsev.rhcloud.com/"; + private static final String BODY_ENCODE = "utf-8"; + + private final String serviceUrl; + + public APIService(User user) { + this.serviceUrl = SERVER_BASE_URL + "user/" + user.getUserId() + "/"; + } + + public > APIRequest getUserNotes() { + HttpGet request = new HttpGet(serviceUrl + "notes"); + request.setHeader("Accept", "application/json"); + + return new APIRequest<>(request, TypeToken.getParameterized(Collection.class, TaskEntry.class).getType()); + } + + public APIRequest getNoteById(int noteId) { + HttpGet request = new HttpGet(serviceUrl + "note/" + noteId); + request.setHeader("Accept", "application/json"); + + return new APIRequest<>(request); + } + + public APIRequest createNote(TaskEntry entry) { + HttpPost request = new HttpPost(serviceUrl + "notes"); + request.setHeader("Accept", "application/json"); + + String json = JSONFactory.toJson(entry, TaskEntry.class); + request.setEntity(new StringEntity(json, BODY_ENCODE)); + + return new APIRequest<>(request, Integer.class); + } + + public APIRequest editNote(TaskEntry entry) { + HttpPost request = new HttpPost(serviceUrl + "note/" + entry.getEntryId()); + request.setHeader("Accept", "application/json"); + + String json = JSONFactory.toJson(entry, TaskEntry.class); + request.setEntity(new StringEntity(json, BODY_ENCODE)); + + return new APIRequest<>(request); + } + + public APIRequest deleteNote(int id) { + HttpDelete request = new HttpDelete(serviceUrl + "note/" + id); + request.setHeader("Accept", "application/json"); + + return new APIRequest<>(request); + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIServiceExecutor.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIServiceExecutor.java new file mode 100644 index 0000000..b848807 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/APIServiceExecutor.java @@ -0,0 +1,204 @@ +package ru.urfu.taskmanager.data.network; + +import android.accounts.NetworkErrorException; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.support.annotation.NonNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import ru.urfu.taskmanager.task_manager.models.TaskEntry; +import ru.urfu.taskmanager.data.db.DbFilter; +import ru.urfu.taskmanager.data.db.DbTasks; +import ru.urfu.taskmanager.data.db.async.AsyncExecutor; +import ru.urfu.taskmanager.data.db.async.DbAsyncExecutor; +import ru.urfu.taskmanager.data.db.async.ExecuteController; +import ru.urfu.taskmanager.data.db.async.ExecuteControllerAdapter; +import ru.urfu.taskmanager.data.network.sync_module.BroadcastSyncManager; +import ru.urfu.taskmanager.utils.tools.NetworkUtil; + +public class APIServiceExecutor implements AsyncExecutor +{ + private Context mContext; + private DbAsyncExecutor mDbAsyncExecutor = DbTasks.getInstance().getAsyncExecutor(); + private APIService mApiService; + + private APICallback mFailedCallback = new APICallback() { + @Override + public void onFailure(Throwable t) { + mContext.sendBroadcast(new Intent(BroadcastSyncManager.SYNC_SCHEDULE_ACTION)); + } + }; + + public APIServiceExecutor(Context context, APIService service) { + this.mContext = context; + this.mApiService = service; + } + + private boolean isConnected() { + boolean isConnected = NetworkUtil.networkIsReachable(mContext); + if (!isConnected) { + mFailedCallback.onFailure(new NetworkErrorException()); + } + + return isConnected; + } + + @Override + public void getAllEntries(@NonNull ExecuteController> controller) { + if (isConnected()) { + controller.onStart(); + mApiService.getUserNotes().send(new APICallback>() + { + @Override + public void onResponse(APIResponse> response) { + controller.onFinish(new ArrayList<>(response.getBody())); + } + + @Override + public void onFailure(Throwable t) { + mFailedCallback.onFailure(t); + } + }); + } else { + mDbAsyncExecutor.getAllEntries(controller); + } + } + + @Override + public void getEntryById(int id, ExecuteController controller) { + if (isConnected()) { + controller.onStart(); + mApiService.getNoteById(id).send(new APICallback() + { + @Override + public void onResponse(APIResponse response) { + controller.onFinish(response.getBody()); + } + + @Override + public void onFailure(Throwable t) { + mFailedCallback.onFailure(t); + } + }); + } else { + mDbAsyncExecutor.getEntryById(id, controller); + } + } + + @Override + public void insertEntry(@NonNull TaskEntry entry) { + if (isConnected()) { + mApiService.createNote(entry).send(new APICallback() + { + @Override + public void onResponse(APIResponse response) { + mDbAsyncExecutor.insertEntry(entry.setEntryId(response.getBody())); + } + + @Override + public void onFailure(Throwable t) { + mFailedCallback.onFailure(t); + } + }); + } else { + mDbAsyncExecutor.insertEntry(entry.setEntryId(-1)); + } + } + + @Override + public void insertEntry(@NonNull TaskEntry entry, @NonNull ExecuteController controller) { + mDbAsyncExecutor.insertEntry(entry, new ExecuteControllerAdapter() + { + @Override + public void onFinish(TaskEntry result) { + controller.onFinish(result); + + if (isConnected()) { + mApiService.createNote(result).send(new APICallback() + { + @Override + public void onResponse(APIResponse response) { + TaskEntry toUpdate = result.setEntryId(response.getBody()); + mDbAsyncExecutor.updateEntry(toUpdate); + } + + @Override + public void onFailure(Throwable t) { + mFailedCallback.onFailure(t); + } + }); + } + } + }); + } + + @Override + public void removeEntryById(int id) { + if (isConnected()) { + mApiService.deleteNote(id).send(mFailedCallback); + } else { + mDbAsyncExecutor.removeEntryById(id); + } + } + + @Override + public void removeEntryById(int id, @NonNull ExecuteController controller) { + controller.onStart(); + mDbAsyncExecutor.removeEntryById(id, new ExecuteControllerAdapter() + { + @Override + public void onFinish(TaskEntry deleted) { + if (isConnected()) { + mApiService.deleteNote(deleted.getEntryId()).send(mFailedCallback); + } + + controller.onFinish(deleted); + } + }); + } + + @Override + public void updateEntry(@NonNull TaskEntry entry) { + mDbAsyncExecutor.updateEntry(entry, new ExecuteControllerAdapter() + { + @Override + public void onFinish(TaskEntry result) { + if (isConnected()) mApiService.editNote(result).send(mFailedCallback); + } + }); + } + + @Override + public void updateEntry(@NonNull TaskEntry entry, @NonNull ExecuteController controller) { + controller.onStart(); + mDbAsyncExecutor.updateEntry(entry, new ExecuteControllerAdapter() + { + @Override + public void onFinish(TaskEntry result) { + controller.onFinish(result); + if (isConnected()) mApiService.editNote(result).send(mFailedCallback); + } + }); + } + + @Override + public void replaceAll(@NonNull List entries, @NonNull ExecuteController controller) { + mDbAsyncExecutor.replaceAll(entries, controller); + } + + @Override + public void getCursor(@NonNull DbFilter filter, @NonNull ExecuteController controller) { + mDbAsyncExecutor.getCursor(filter, controller); + } + + @Override + public void startTransaction(ExecuteController controller) { + mDbAsyncExecutor.startTransaction(controller); + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/sync_module/BroadcastSyncManager.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/sync_module/BroadcastSyncManager.java new file mode 100644 index 0000000..3558823 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/sync_module/BroadcastSyncManager.java @@ -0,0 +1,170 @@ +package ru.urfu.taskmanager.data.network.sync_module; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +import com.github.javiersantos.bottomdialogs.BottomDialog; + +import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.auth.models.User; +import ru.urfu.taskmanager.task_manager.models.TaskEntry; +import ru.urfu.taskmanager.task_manager.models.TaskEntryCouples; +import ru.urfu.taskmanager.utils.tools.NetworkUtil; + +public abstract class BroadcastSyncManager extends BroadcastReceiver +{ + public static final String SYNC_AT_FIRST_TIME_KEY = "ru.urfu.taskmanager.SYNC_AT_FIRST_TIME_KEY"; + + public static final int SYNC_SCHEDULED = 1; + public static final int SYNC_NOT_SCHEDULED = 2; + public static final int SYNC_AT_FIRST_TIME = 3; + + public static final String SYNC_SCHEDULE_ACTION = "ru.urfu.taskmanager.SYNC_SCHEDULE_ACTION"; + public static final String SYNC_SUCCESS_ACTION = "ru.urfu.taskmanager.SYNC_SUCCESS_ACTION"; + public static final String SYNC_FAILED_ACTION = "ru.urfu.taskmanager.SYNC_FAILED_ACTION"; + public static final String SYNC_START_ACTION = "ru.urfu.taskmanager.SYNC_START_ACTION"; + public static final String SYNC_ASK_ACTION = "ru.urfu.taskmanager.SYNC_ASK_ACTION"; + + public static final String REPOSITORY_NAME = "ru.urfu.taskmanager.API_SYNC"; + + private Context mContext; + private MergeConflictsSolver mMergeConflictsSolver; + private SharedPreferences mSyncRepository; + + public BroadcastSyncManager(Activity activity) { + this.mContext = activity; + this.mSyncRepository = mContext.getSharedPreferences(REPOSITORY_NAME, Context.MODE_PRIVATE); + } + + @Override + public final void onReceive(final Context context, final Intent data) { + switch (data.getAction()) { + case SYNC_SCHEDULE_ACTION: + onScheduleSync(); + break; + case SYNC_SUCCESS_ACTION: + unScheduleSync(); + onStopSync(); + break; + case SYNC_FAILED_ACTION: + Toast.makeText(context, context.getString(R.string.sync_failed), Toast.LENGTH_SHORT).show(); + onScheduleSync(); + onStopSync(); + break; + case SYNC_ASK_ACTION: + Bundle bundle = data.getExtras(); + startConflictsSolver(bundle.getParcelable(SynchronizeService.EXTRA_KEY)); + break; + case SYNC_START_ACTION: + synchronizeData(SYNC_SCHEDULED); + break; + case ConnectivityManager.CONNECTIVITY_ACTION: + synchronizeDataIfScheduled(); + break; + } + } + + public final void startConflictsSolver(TaskEntryCouples mergeCouples) { + + mMergeConflictsSolver = new MergeConflictsSolver(mContext, mergeCouples); + + for (TaskEntryCouples.Couple couple : mergeCouples) + { + LayoutInflater inflater = LayoutInflater.from(mContext); + View view = inflater.inflate(R.layout.sync_conflict_layout, null); + + ViewGroup leftLayout = (ViewGroup) view.findViewById(R.id.first_container); + ViewGroup rightLayout = (ViewGroup) view.findViewById(R.id.second_container); + + fillLayout(leftLayout, couple.getKey()); + fillLayout(rightLayout, couple.getValue()); + + BottomDialog solverDialog = new BottomDialog.Builder(mContext) + .setTitle(mContext.getString(R.string.merge_conflict_title)) + .setContent(mContext.getString(R.string.merge_conflict_descr)) + .setCustomView(view) + .setCancelable(false) + .build(); + + + leftLayout.setOnClickListener(mMergeConflictsSolver.with(couple, MergeConflictsSolver.LOCAL, + aVoid -> solverDialog.dismiss()) + ); + + rightLayout.setOnClickListener(mMergeConflictsSolver.with(couple, MergeConflictsSolver.REMOTE, + aVoid -> solverDialog.dismiss()) + ); + + solverDialog.show(); + } + } + + public abstract void onStopSync(); + + private void fillLayout(ViewGroup viewGroup, TaskEntry entry) { + viewGroup.addView(createTextView("Title: " + entry.getTitle())); + viewGroup.addView(createTextView("Descr: " + entry.getDescription())); + viewGroup.addView(createTextView("Created: " + entry.getCreated())); + viewGroup.addView(createTextView("Edited: " + entry.getEdited())); + viewGroup.addView(createTextView("Viewed: " + entry.getTtl())); + viewGroup.addView(createTextView("ImgUrl: " + entry.getImageUrl())); + viewGroup.addView(createTextView("Color: " + entry.getColor())); + } + + private TextView createTextView(String text) { + TextView textView = new TextView(mContext); + textView.setText(text); + return textView; + } + + private void onScheduleSync() { + if (mMergeConflictsSolver != null) + mMergeConflictsSolver.conflictWasNotResolved(); + + mSyncRepository.edit() + .putInt(User.getActiveUser().getLogin(), SYNC_SCHEDULED) + .apply(); + } + + private void unScheduleSync() { + mSyncRepository.edit() + .putInt(User.getActiveUser().getLogin(), SYNC_NOT_SCHEDULED) + .apply(); + + Toast.makeText(mContext, mContext.getString(R.string.sync_success), Toast.LENGTH_SHORT).show(); + } + + private void synchronizeDataIfScheduled() { + int type = mSyncRepository.getInt(User.getActiveUser().getLogin(), SYNC_AT_FIRST_TIME); + synchronizeData(type); + } + + private void synchronizeData(int type) { + if (NetworkUtil.networkIsReachable(mContext)) { + switch (type) { + case SYNC_SCHEDULED: + Toast.makeText(mContext, mContext.getString(R.string.sync_title), Toast.LENGTH_SHORT).show(); + mContext.startService(new Intent(mContext, SynchronizeService.class)); + break; + case SYNC_AT_FIRST_TIME: + Toast.makeText(mContext, mContext.getString(R.string.sync_title), Toast.LENGTH_SHORT).show(); + Intent intent = new Intent(mContext, SynchronizeService.class); + intent.putExtra(SYNC_AT_FIRST_TIME_KEY, true); + mContext.startService(intent); + break; + } + } else if (type == SYNC_AT_FIRST_TIME) { + onScheduleSync(); + } + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/sync_module/MergeConflictsSolver.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/sync_module/MergeConflictsSolver.java new file mode 100644 index 0000000..9896b08 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/sync_module/MergeConflictsSolver.java @@ -0,0 +1,89 @@ +package ru.urfu.taskmanager.data.network.sync_module; + +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.List; + +import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.auth.models.User; +import ru.urfu.taskmanager.data.network.APIServiceExecutor; +import ru.urfu.taskmanager.task_manager.models.TaskEntryCouples; +import ru.urfu.taskmanager.utils.interfaces.Callback; + +public final class MergeConflictsSolver +{ + public static final int LOCAL = 1; + public static final int REMOTE = 2; + + private Context mContext; + private TaskEntryCouples mCouples; + private List mListeners; + + private boolean isResolved = true; + + public MergeConflictsSolver(Context context, TaskEntryCouples couples) { + this.mContext = context; + this.mCouples = couples; + this.mListeners = new ArrayList<>(); + } + + public OnSolveListener with(TaskEntryCouples.Couple couple, int type, Callback callback) { + OnSolveListener onSolveListener = new OnSolveListener(couple, type, callback); + mListeners.add(onSolveListener); + return onSolveListener; + } + + public void conflictWasNotResolved() { + isResolved = false; + + for (OnSolveListener mListener : mListeners) { + mListener.mCallback.call(null); + } + + Toast.makeText(mContext, mContext.getString(R.string.conflict_not_resolved), Toast.LENGTH_SHORT).show(); + } + + private class OnSolveListener implements View.OnClickListener + { + int mType; + TaskEntryCouples.Couple mCouple; + Callback mCallback; + + APIServiceExecutor mApiService; + + OnSolveListener(TaskEntryCouples.Couple couple, int type, Callback callback) { + this.mType = type; + this.mCouple = couple; + this.mCallback = callback; + this.mApiService = User.getActiveUser() + .getExecutor(); + } + + @Override + public void onClick(View v) { + switch (mType) { + case LOCAL: + mApiService.updateEntry(mCouple.getKey()); + break; + case REMOTE: + mApiService.updateEntry(mCouple.getValue() + .setId(mCouple.getKey().getId()) + .setDeviceIdentifier(User.getActiveUser().getDeviceIdentifier()) + ); + break; + } + + MergeConflictsSolver.this.mCouples.remove(mCouple); + if (MergeConflictsSolver.this.mCouples.size() == 0 && isResolved) { + MergeConflictsSolver.this.mContext + .sendBroadcast(new Intent(BroadcastSyncManager.SYNC_SUCCESS_ACTION)); + } + + mCallback.call(null); + } + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/sync_module/SynchronizeService.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/sync_module/SynchronizeService.java new file mode 100644 index 0000000..a370985 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/data/network/sync_module/SynchronizeService.java @@ -0,0 +1,197 @@ +package ru.urfu.taskmanager.data.network.sync_module; + +import android.app.Service; +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; +import android.support.annotation.Nullable; +import android.util.SparseArray; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +import ru.urfu.taskmanager.auth.models.User; +import ru.urfu.taskmanager.task_manager.models.TaskEntry; +import ru.urfu.taskmanager.data.db.DbTasks; +import ru.urfu.taskmanager.task_manager.models.TaskEntryCouples; +import ru.urfu.taskmanager.data.network.APICallback; +import ru.urfu.taskmanager.data.network.APIResponse; +import ru.urfu.taskmanager.data.network.APIService; +import ru.urfu.taskmanager.utils.interfaces.Callback; +import ru.urfu.taskmanager.utils.interfaces.Thenable; + +public class SynchronizeService extends Service implements Thenable +{ + public static final String EXTRA_KEY = "data"; + + private TaskEntryCouples mDisputableEntries; + private SparseArray mRemoteMapEntries; + + private APIService mApiService; + private DbTasks mDatabase; + + @Override + public void onCreate() { + super.onCreate(); + mDisputableEntries = new TaskEntryCouples(); + mRemoteMapEntries = new SparseArray<>(); + mApiService = User.getActiveUser().getService(); + mDatabase = DbTasks.getInstance(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) + { + boolean loadAll = intent.getBooleanExtra(BroadcastSyncManager.SYNC_AT_FIRST_TIME_KEY, false); + + if (loadAll) { + loadDataProcess(); + } else { + startSyncProcess(); + } + + return START_NOT_STICKY; + } + + private void loadDataProcess() { + + mApiService.getUserNotes().send(new APICallback>() + { + @Override + public void onResponse(APIResponse> response) { + mDatabase.startTransaction(aVoid -> { + for (TaskEntry entry : response.getBody()) { + mDatabase.insertEntry(entry); + } + }); + + SynchronizeService.this.onSuccess(); + } + + @Override + public void onFailure(Throwable t) { + SynchronizeService.this.onFailed(t); + } + }); + } + + private void startSyncProcess() { + List localEntries = mDatabase.getAllEntries(); + + mApiService.getUserNotes().send(new APICallback>() + { + @Override + public void onResponse(APIResponse> response) + { + for (TaskEntry entry : response.getBody()) { + mRemoteMapEntries.put(entry.getEntryId(), entry); + } + + Queue localQueue = new ConcurrentLinkedQueue<>(localEntries); + while (!localQueue.isEmpty()) + { + TaskEntry localEntry = localQueue.poll(); + TaskEntry remoteEntry = mRemoteMapEntries.get(localEntry.getEntryId()); + + if (remoteEntry != null) { + System.out.println("local: " + localEntry.getTtlTimestamp()); + System.out.println("remote: " + remoteEntry.getTtlTimestamp()); + if (localEntry.hashCode() == remoteEntry.hashCode()) { + System.out.println("continue"); + mRemoteMapEntries.remove(localEntry.getEntryId()); + continue; + } + + if (localEntry.getDeviceIdentifier().equals(remoteEntry.getDeviceIdentifier())) { + if (localEntry.getEditedTimestamp() > remoteEntry.getEditedTimestamp()) { + mApiService.editNote(localEntry).send(new APICallback() + { + @Override + public void onFailure(Throwable t) { + SynchronizeService.this.onFailed(t); + } + }); + } else { + mDisputableEntries.put(localEntry, remoteEntry); + } + } else { + mDisputableEntries.put(localEntry, remoteEntry); + } + + mRemoteMapEntries.remove(localEntry.getEntryId()); + } else { + mApiService.createNote(localEntry).send(new APICallback() + { + @Override + public void onResponse(APIResponse response) { + mDatabase.updateEntry(localEntry.setEntryId(response.getBody())); + } + + @Override + public void onFailure(Throwable t) { + SynchronizeService.this.onFailed(t); + } + }); + } + } + + while (mRemoteMapEntries.size() != 0) { + TaskEntry remoteEntry = mRemoteMapEntries.valueAt(0); + if (remoteEntry.getDeviceIdentifier().equals(User.getActiveUser().getDeviceIdentifier())) { + mApiService.deleteNote(remoteEntry.getEntryId()).send(new APICallback() + { + @Override + public void onFailure(Throwable t) { + SynchronizeService.this.onFailed(t); + } + }); + } else { + mDatabase.insertEntry(remoteEntry); + } + + mRemoteMapEntries.removeAt(0); + } + + SynchronizeService.this.onSuccess(); + } + + @Override + public void onFailure(Throwable t) { + SynchronizeService.this.onFailed(t); + } + }); + } + + @Override + public void onSuccess(Void... results) { + if (!mDisputableEntries.isEmpty()) { + Bundle bundle = new Bundle(); + bundle.putParcelable(EXTRA_KEY, mDisputableEntries); + + Intent intent = new Intent(BroadcastSyncManager.SYNC_ASK_ACTION); + intent.putExtras(bundle); + + sendBroadcast(intent); + } else { + sendBroadcast(new Intent(BroadcastSyncManager.SYNC_SUCCESS_ACTION)); + } + + stopSelf(); + } + + @Override + public void onFailed(Throwable t) { + t.printStackTrace(); + sendBroadcast(new Intent(BroadcastSyncManager.SYNC_FAILED_ACTION)); + stopSelf(); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/presenter/TaskEditorPresenter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/presenter/TaskEditorPresenter.java similarity index 68% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/presenter/TaskEditorPresenter.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/presenter/TaskEditorPresenter.java index e63d2c1..086eaec 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/presenter/TaskEditorPresenter.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/presenter/TaskEditorPresenter.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.task_manager.task_editor.presenter; +package ru.urfu.taskmanager.task_manager.editor.presenter; import ru.urfu.taskmanager.task_manager.models.TaskEntry; diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/presenter/TaskEditorPresenterImpl.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/presenter/TaskEditorPresenterImpl.java new file mode 100644 index 0000000..88014bf --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/presenter/TaskEditorPresenterImpl.java @@ -0,0 +1,111 @@ +package ru.urfu.taskmanager.task_manager.editor.presenter; + +import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.auth.models.User; +import ru.urfu.taskmanager.color_picker.recent.RecentColorsStorage; +import ru.urfu.taskmanager.task_manager.models.TaskEntry; +import ru.urfu.taskmanager.task_manager.editor.view.TaskEditor; +import ru.urfu.taskmanager.data.db.DbTasks; +import ru.urfu.taskmanager.data.network.APIServiceExecutor; +import ru.urfu.taskmanager.data.db.async.DbAsyncExecutor; +import ru.urfu.taskmanager.data.db.async.ExecuteControllerAdapter; +import ru.urfu.taskmanager.utils.interfaces.Callback; + +import static android.app.Activity.RESULT_OK; +import static ru.urfu.taskmanager.task_manager.editor.view.TaskEditorFragment.NON_ID; + +public class TaskEditorPresenterImpl implements TaskEditorPresenter +{ + private int mItemId; + private int mEntryId; + + private TaskEditor mEditor; + private TaskValidator mValidator; + private DbAsyncExecutor mDbAsyncExecutor; + private APIServiceExecutor mAPIServiceExecutor; + private RecentColorsStorage mRecentColorsStorage; + + public TaskEditorPresenterImpl(TaskEditor editor) { + this.mEditor = editor; + this.mItemId = NON_ID; + this.mAPIServiceExecutor = User.getActiveUser().getExecutor(); + this.mDbAsyncExecutor = DbTasks.getInstance().getAsyncExecutor(); + this.mRecentColorsStorage = RecentColorsStorage.getRepository(); + this.mValidator = new TaskValidator(); + init(); + } + + private void init() { + if (mEditor.getEditedItemId() != NON_ID) { + mItemId = mEditor.getEditedItemId(); + + mDbAsyncExecutor.getEntryById(mItemId, + new ExecuteControllerAdapter() { + @Override + public void onFinish(TaskEntry result) { + mEntryId = result.getEntryId(); + mEditor.initializeEditor(result); + mEditor.onImageLoad(result.getImageUrl()); + } + }); + } + } + + @Override + public void saveState(TaskEntry state) { + ExecuteControllerAdapter onPostExecute = new ExecuteControllerAdapter() { + @Override + public void onFinish() { + mRecentColorsStorage.putItem(state.getColorInt()); + mEditor.exit(RESULT_OK); + } + }; + + mValidator.validate(state, aVoid -> { + long timestamp = System.currentTimeMillis(); + state.setId(mItemId).setEntryId(mEntryId).setEdited(timestamp); + + switch (mItemId) { + case NON_ID: + mAPIServiceExecutor.insertEntry(state.setCreated(timestamp), onPostExecute); + break; + default: + mAPIServiceExecutor.updateEntry(state, onPostExecute); + break; + } + }); + } + + private class TaskValidator { + private static final int TITLE_MAX_LENGTH = 20; + private static final int DESCRIPTION_MAX_LENGTH = 50; + + private boolean isValid = true; + + private void validate(TaskEntry entry, Callback callback) { + isValid = true; + + if (entry.getTitle().isEmpty()) { + isValid = false; + mEditor.showTitleError(mEditor.getString(R.string.search_hint)); + } + + if (entry.getTitle().length() > TITLE_MAX_LENGTH) { + isValid = false; + mEditor.showTitleError(mEditor.getString(R.string.incorrect_length) + " " + TITLE_MAX_LENGTH); + } + + if (entry.getDescription().isEmpty()) { + isValid = false; + mEditor.showDescriptionError(mEditor.getString(R.string.entry_description)); + } + + if (entry.getDescription().length() > DESCRIPTION_MAX_LENGTH) { + isValid = false; + mEditor.showTitleError(mEditor.getString(R.string.incorrect_length) + " " + DESCRIPTION_MAX_LENGTH); + } + + if (isValid) callback.call(null); + } + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/tools/ImageLoader.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/tools/ImageLoader.java similarity index 82% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/tools/ImageLoader.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/tools/ImageLoader.java index f05567b..d2a4d37 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/tools/ImageLoader.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/tools/ImageLoader.java @@ -1,4 +1,4 @@ -package ru.urfu.taskmanager.task_manager.task_editor.tools; +package ru.urfu.taskmanager.task_manager.editor.tools; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -47,8 +47,9 @@ public void from(String url) { mBitmap = BitmapFactory.decodeStream(mImageUrl.openConnection().getInputStream()); mView.post(() -> mView.setImageBitmap(mBitmap)); } catch (IOException e) { - mView.post(() -> Toast.makeText(mView.getContext(), - mView.getResources().getString(R.string.could_not_load_image), Toast.LENGTH_SHORT).show()); + e.printStackTrace(); +// mView.post(() -> Toast.makeText(mView.getContext(), +// mView.getResources().getString(R.string.could_not_load_image), Toast.LENGTH_SHORT).show()); } finally { quit(); } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/view/EditorPagerFragment.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/view/EditorPagerFragment.java new file mode 100644 index 0000000..67a77f5 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/view/EditorPagerFragment.java @@ -0,0 +1,90 @@ +package ru.urfu.taskmanager.task_manager.editor.view; + +import android.database.Cursor; +import android.os.Bundle; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.view.View; + +import ru.urfu.taskmanager.data.db.DbTasks; +import ru.urfu.taskmanager.data.db.DbTasksFilter; +import ru.urfu.taskmanager.task_manager.main.fragments.helper.CursorProvider; +import ru.urfu.taskmanager.task_manager.main.fragments.TaskPagerFragment; +import ru.urfu.taskmanager.task_manager.models.TaskEntry; + +import static ru.urfu.taskmanager.task_manager.editor.view.TaskEditorFragment.EDITED_ITEM_ID_KEY; +import static ru.urfu.taskmanager.task_manager.editor.view.TaskEditorFragment.TRANSITION_NAME; + +public class EditorPagerFragment extends TaskPagerFragment +{ + public static final String EDITOR_PAGER_POSITION = "ru.urfu.taskmanager.task_manager.editor.EDITOR_PAGER_POSITION"; + + CursorProvider mDataAdapter; + DbTasks mDatabase; + + private EditorPagerFragment(CursorProvider adapter) { + mDataAdapter = adapter; + mDatabase = DbTasks.getInstance(); + } + + @Override + protected void configViewPager() { + super.configViewPager(); + Integer position = (Integer) getArguments().getSerializable(EDITOR_PAGER_POSITION); + position = (position != null) ? position : 0; + mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); + mViewPager.setCurrentItem(position); + fab.setVisibility(View.GONE); + } + + @Override + protected FragmentStatePagerAdapter getPagerAdapter() { + return new EditorPagerAdapter(getChildFragmentManager()); + } + + public static EditorPagerFragment newInstance(Bundle args, CursorProvider adapter) { + EditorPagerFragment fragment = new EditorPagerFragment(adapter); + fragment.setArguments(args); + return fragment; + } + + private class EditorPagerAdapter extends FragmentStatePagerAdapter + { + private Cursor cursor; + + public EditorPagerAdapter(FragmentManager fm) { + super(fm); + cursor = (mDataAdapter != null) + ? mDataAdapter.getCursor() + : mDatabase.getCursor(DbTasksFilter.DEFAULT_BUILDER.build()); + } + + @Override + public Fragment getItem(int position) { + int editedItemId = getEntryFromPosition(position) + .getId(); + + Bundle bundle = new Bundle(); + bundle.putInt(EDITED_ITEM_ID_KEY, editedItemId); + bundle.putString(TRANSITION_NAME, "timeBlock_" + position); + return TaskEditorFragment.newInstance(bundle); + } + + @Override + public int getCount() { + return cursor.getCount(); + } + + @Override + public CharSequence getPageTitle(int position) { + return getEntryFromPosition(position).getTitle(); + } + + private TaskEntry getEntryFromPosition(int position) { + cursor.moveToPosition(position); + return mDatabase.getCurrentEntryFromCursor(cursor); + } + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/view/TaskEditor.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/view/TaskEditor.java similarity index 61% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/view/TaskEditor.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/view/TaskEditor.java index 294f253..48f8349 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/view/TaskEditor.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/view/TaskEditor.java @@ -1,19 +1,16 @@ -package ru.urfu.taskmanager.task_manager.task_editor.view; +package ru.urfu.taskmanager.task_manager.editor.view; -import android.content.Intent; +import android.support.annotation.StringRes; import android.view.View; import ru.urfu.taskmanager.color_picker.listeners.PickerViewStateListener; import ru.urfu.taskmanager.task_manager.models.TaskEntry; -import ru.urfu.taskmanager.utils.interfaces.ActivityWindow; -public interface TaskEditor extends View.OnClickListener, PickerViewStateListener, ActivityWindow +public interface TaskEditor extends View.OnClickListener, PickerViewStateListener { - Intent getIntent(); + int getEditedItemId(); - boolean isRestored(); - - void setToolbarTitle(String title); + String getString(@StringRes int stringRes); void initializeEditor(TaskEntry entryToEdit); diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/view/TaskEditorFragment.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/view/TaskEditorFragment.java new file mode 100644 index 0000000..3426bb1 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/editor/view/TaskEditorFragment.java @@ -0,0 +1,229 @@ +package ru.urfu.taskmanager.task_manager.editor.view; + +import android.graphics.Color; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Vibrator; +import android.support.annotation.Nullable; +import android.support.annotation.StringRes; +import android.support.design.widget.TextInputLayout; +import android.support.v4.app.Fragment; +import android.support.v4.view.ViewCompat; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; + +import com.github.florent37.singledateandtimepicker.SingleDateAndTimePicker; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.color_picker.PickerView; +import ru.urfu.taskmanager.color_picker.recent.RecentColors; +import ru.urfu.taskmanager.task_manager.editor.presenter.TaskEditorPresenter; +import ru.urfu.taskmanager.task_manager.editor.presenter.TaskEditorPresenterImpl; +import ru.urfu.taskmanager.task_manager.editor.tools.ImageLoader; +import ru.urfu.taskmanager.task_manager.main.view.TaskManager; +import ru.urfu.taskmanager.task_manager.models.TaskEntry; +import ru.urfu.taskmanager.utils.tools.TimeUtils; + +import static android.content.Context.VIBRATOR_SERVICE; +import static ru.urfu.taskmanager.task_manager.main.view.TaskManagerActivity.REQUEST_CREATE; +import static ru.urfu.taskmanager.task_manager.main.view.TaskManagerActivity.REQUEST_EDIT; + +public class TaskEditorFragment extends Fragment implements TaskEditor, SingleDateAndTimePicker.Listener +{ + public static final int NON_ID = -1; + public static final String EDITED_ITEM_ID_KEY = "ru.urfu.taskmanager.task_manager.editor.EDITED_ITEM_ID"; + public static final String TRANSITION_NAME = "transitionName"; + + private static final int CELL_COUNT = 16; + + TaskManager mManager; + TaskEditorPresenter mPresenter; + + SingleDateAndTimePicker mDateTimePicker; + TextInputLayout mTitleInputLayout; + TextInputLayout mDescInputLayout; + ImageView mImageView; + PickerView mPickerView; + TextView mColorDeadlineTextView; + EditText mTitleEditField; + EditText mDescEditField; + EditText mImageUrlEditField; + Button mButtonSave; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return initView(inflater.inflate(R.layout.activity_task_editor, container, false)); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + initialize(); + } + + private View initView(View view) { + mDateTimePicker = (SingleDateAndTimePicker) view.findViewById(R.id.datetime_picker); + mColorDeadlineTextView = (TextView) view.findViewById(R.id.color_deadline); + mButtonSave = (Button) view.findViewById(R.id.save_button); + mDescEditField = (EditText) view.findViewById(R.id.descr_edit_field); + mDescInputLayout = (TextInputLayout) view.findViewById(R.id.description_input_layout); + mTitleEditField = (EditText) view.findViewById(R.id.title_edit_field); + mTitleInputLayout = (TextInputLayout) view.findViewById(R.id.title_input_layout); + mImageUrlEditField = (EditText) view.findViewById(R.id.image_url_edit_field); + mImageView = (ImageView) view.findViewById(R.id.image_view); + mPickerView = (PickerView) view.findViewById(R.id.pickerView); + + mImageUrlEditField.addTextChangedListener(new TextWatcher() + { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + onImageLoad(s.toString()); + } + }); + + ViewCompat.setTransitionName(mColorDeadlineTextView, getArguments().getString(TRANSITION_NAME)); + + return view; + } + + @Override + public int getEditedItemId() { + Integer valueId = (Integer) getArguments().getSerializable(EDITED_ITEM_ID_KEY); + return (valueId != null) ? valueId : NON_ID; + } + + private void initialize() { + mManager = (TaskManager) getActivity(); + + mDateTimePicker.setMustBeOnFuture(true); + mDateTimePicker.setListener(this); + + mButtonSave.setOnClickListener(this); + mPickerView.setCellCount(CELL_COUNT); + mPickerView.subscribe(this); + + onColorChanged(mPickerView.getCurrentColor()); + mColorDeadlineTextView.setOnClickListener(v -> RecentColors.showRecent(getContext(), color -> { + mPickerView.setCurrentColor(color); + onColorChanged(color); + })); + + mPresenter = new TaskEditorPresenterImpl(this); + } + + public void initializeEditor(TaskEntry entry) { + getActivity().runOnUiThread(() -> { + Calendar calendar = new GregorianCalendar(); + calendar.setTimeInMillis(entry.getTtlTimestamp()); + + mDateTimePicker.selectDate(calendar); + mDateTimePicker.setSelectorColor(Color.BLACK); + mTitleEditField.setText(entry.getTitle()); + mDescEditField.setText(entry.getDescription()); + mImageUrlEditField.setText(entry.getImageUrl()); + mPickerView.setCurrentColor(entry.getColorInt()); + mColorDeadlineTextView.setText(TimeUtils.getHoursAndMinutesFromUnix(entry.getTtlTimestamp()).toString()); + onColorChanged(mPickerView.getCurrentColor()); + }); + } + + @Override + public void onImageLoad(String url) { + mImageView.post(() -> ImageLoader.into(mImageView) + .from(url)); + } + + @Override + public void showTitleError(String string) { + mTitleInputLayout.setError(string); + } + + @Override + public void showDescriptionError(String string) { + mDescInputLayout.setError(string); + } + + @Override + public void onClick(View v) { + mTitleInputLayout.setErrorEnabled(false); + mDescInputLayout.setErrorEnabled(false); + + mPresenter.saveState( + new TaskEntry() + .setTitle(mTitleEditField.getText().toString()) + .setDescription(mDescEditField.getText().toString()) + .setTtl(mDateTimePicker.getDate().getTime()) + .setColor(mPickerView.getCurrentColor()) + .setImageUrl(mImageUrlEditField.getText().toString()) + ); + } + + @Override + public void onColorChanged(int color) { + GradientDrawable gd = new GradientDrawable(); + gd.setColor(color); + gd.setCornerRadius(100f); + + mColorDeadlineTextView.setBackground(gd); + } + + @Override + public void editModeEnable() { + vibrate(); + } + + @Override + public void editModeDisable() { + vibrate(); + } + + @Override + public void theBoundaryIsReached() { + vibrate(); + } + + @Override + public void exit(int result) { + mManager.getPresenter() + .onResult((getEditedItemId() == NON_ID) ? REQUEST_CREATE : REQUEST_EDIT); + + mManager.getSupportFragmentManager() + .popBackStack(); + } + + private void vibrate() { + Vibrator vibrator = (Vibrator) getContext().getSystemService(VIBRATOR_SERVICE); + vibrator.vibrate(10); + } + + @Override + public void onDateChanged(String displayed, Date date) { + mColorDeadlineTextView.setText(TimeUtils.getHoursAndMinutesFromUnix(date.getTime()).toString()); + } + + public static TaskEditorFragment newInstance(@Nullable Bundle args) { + TaskEditorFragment fragment = new TaskEditorFragment(); + if (args != null) fragment.setArguments(args); + return fragment; + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/adapters/AbstractTaskListAdapter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/adapters/AbstractTaskListAdapter.java deleted file mode 100644 index 6ec5278..0000000 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/adapters/AbstractTaskListAdapter.java +++ /dev/null @@ -1,42 +0,0 @@ -package ru.urfu.taskmanager.task_manager.fragments.adapters; - -import android.content.Context; -import android.database.Cursor; -import android.widget.SimpleCursorAdapter; - -import ru.urfu.taskmanager.R; -import ru.urfu.taskmanager.utils.db.DbTasksHelper; - - -public class AbstractTaskListAdapter extends SimpleCursorAdapter -{ - protected static final String OVERDUE = "Просрочено"; - - protected static final int LAYOUT = R.layout.task_list_item; - - protected static final String[] FROM = new String[]{ - DbTasksHelper.TITLE, - DbTasksHelper.DESCRIPTION, - DbTasksHelper.TTL, - DbTasksHelper.DECORATE_COLOR, - }; - - protected static final int[] TO = new int[]{ - R.id.task_item_title, - R.id.task_item_description, - R.id.task_item_deadline, - R.id.task_item_color - }; - - protected static final String[] ACTIVE_DAYS = new String[]{ - "Сегодня", "Завтра", "Послезавтра" - }; - - protected static final String[] COMPLETED_DAYS = new String[]{ - "Сегодня", "Вчера", "Позавчера" - }; - - protected AbstractTaskListAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) { - super(context, layout, c, from, to, flags); - } -} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/adapters/TasksListAdapter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/adapters/TasksListAdapter.java deleted file mode 100644 index a82cb14..0000000 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/adapters/TasksListAdapter.java +++ /dev/null @@ -1,141 +0,0 @@ -package ru.urfu.taskmanager.task_manager.fragments.adapters; - -import android.content.Context; -import android.database.Cursor; -import android.graphics.drawable.GradientDrawable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import java.util.Calendar; - -import ru.urfu.taskmanager.R; -import ru.urfu.taskmanager.task_manager.models.TaskEntry; -import ru.urfu.taskmanager.utils.db.DbTasks; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; -import ru.urfu.taskmanager.utils.tools.TimeUtils; - -public class TasksListAdapter extends AbstractTaskListAdapter -{ - private final Context mContext; - private final DbTasksFilter defaultFilter; - private final DbTasks mDatabase; - - public TasksListAdapter(Context context, DbTasksFilter tasksFilter) { - super(context, LAYOUT, null, FROM, TO, 0); - this.mContext = context; - this.defaultFilter = tasksFilter; - this.mDatabase = DbTasks.getInstance(); - updateData(mDatabase.getCursor(defaultFilter)); - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View view = inflater.inflate(LAYOUT, parent, false); - - ViewHolder holder = new ViewHolder(); - holder.layout = view.findViewById(R.id.task_layout); - holder.header = view.findViewById(R.id.task_header); - holder.header_text = (TextView) view.findViewById(R.id.header_text); - holder.title = (TextView) view.findViewById(R.id.task_item_title); - holder.description = (TextView) view.findViewById(R.id.task_item_description); - holder.ttl = (TextView) view.findViewById(R.id.task_item_deadline); - - view.setTag(holder); - return view; - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - TaskEntry entry = mDatabase.getCurrentEntryFromCursor(cursor); - TaskEntry prev = (cursor.moveToPrevious()) - ? mDatabase.getCurrentEntryFromCursor(cursor) - : null; - - GradientDrawable gd = new GradientDrawable(); - gd.setColor(entry.getColorInt()); - gd.setCornerRadius(100f); - - ViewHolder holder = (ViewHolder) view.getTag(); - - holder.title.setText(entry.getTitle()); - holder.description.setText(entry.getDescription()); - holder.ttl.setText(TimeUtils.getHoursAndMinutesFromUnix(entry.getTtlTimestamp()).toString()); - holder.ttl.setBackground(gd); - attachHeader(holder, entry, prev); - } - - private ViewHolder attachHeader(ViewHolder holder, TaskEntry entry, TaskEntry prev) { - String entryTitle = getTitleFromEntry(entry); - if (entryTitle.equals(OVERDUE)) - holder.layout.setAlpha(0.4f); - else holder.layout.setAlpha(1f); - - if (prev != null) { - String prevTitle = getTitleFromEntry(prev); - - if (!entryTitle.equals(prevTitle)) { - holder.header_text.setText(entryTitle); - holder.header.setVisibility(View.VISIBLE); - } else { - holder.header.setVisibility(View.GONE); - } - } else { - holder.header_text.setText(entryTitle); - holder.header.setVisibility(View.VISIBLE); - } - - return holder; - } - - private String getTitleFromEntry(TaskEntry entry) { - if (System.currentTimeMillis() > entry.getTtlTimestamp() & defaultFilter.getType() == DbTasksFilter.ACTIVE_TASK) { - return OVERDUE; - } else { - Calendar entryDate = Calendar.getInstance(); - entryDate.setTimeInMillis(entry.getTtlTimestamp()); - int diffDay = Math.abs(entryDate.get(Calendar.DAY_OF_YEAR) - Calendar.getInstance().get(Calendar.DAY_OF_YEAR)); - return getHeaderTitleByNum(diffDay, entryDate); - } - } - - private String getHeaderTitleByNum(int num, Calendar entryDate) { - if (num < 3) { - switch (defaultFilter.getType()) { - case DbTasksFilter.ACTIVE_TASK: - return ACTIVE_DAYS[num]; - case DbTasksFilter.COMPLETED_TASK: - return COMPLETED_DAYS[num]; - } - } - - return TimeUtils.format(entryDate); - } - - public void updateData(Cursor... cursor) { - if (cursor.length == 0) { - updateCursor(mDatabase.getCursor(defaultFilter)); - } else { - updateCursor(cursor[0]); - } - } - - private void updateCursor(Cursor cursor) { - changeCursor(cursor); - } - - public int getDataType() { - return defaultFilter.getType(); - } - - private static class ViewHolder { - View layout; - View header; - TextView header_text; - TextView title; - TextView description; - TextView ttl; - } -} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListFragment.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListFragment.java deleted file mode 100644 index eb2bf92..0000000 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListFragment.java +++ /dev/null @@ -1,90 +0,0 @@ -package ru.urfu.taskmanager.task_manager.fragments.view; - -import android.content.Intent; -import android.database.Cursor; -import android.os.Bundle; -import android.support.design.widget.Snackbar; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ListView; - -import ru.urfu.taskmanager.R; -import ru.urfu.taskmanager.task_manager.fragments.adapters.TasksListAdapter; -import ru.urfu.taskmanager.task_manager.main.presenter.TaskManagerPresenter; -import ru.urfu.taskmanager.task_manager.task_editor.view.TaskEditorActivity_; -import ru.urfu.taskmanager.utils.db.DbTasksHelper; - -import static ru.urfu.taskmanager.task_manager.main.view.TaskManagerActivity.ACTION_EDIT; -import static ru.urfu.taskmanager.task_manager.main.view.TaskManagerActivity.REQUEST_EDIT; - -public abstract class TaskListFragment extends Fragment - implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, TaskListView -{ - protected TaskManagerPresenter mPresenter; - - ListView mTaskListView; - TasksListAdapter mAdapter; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.active_tasks_fragment, container, false); - return initView(view); - } - - protected View initView(View root) { - mTaskListView = (ListView) root.findViewById(R.id.task_list); - mTaskListView.setAdapter(mAdapter = getAdapter()); - mTaskListView.setOnItemClickListener(this); - mTaskListView.setOnItemLongClickListener(this); - - return root; - } - - protected abstract TasksListAdapter getAdapter(); - - public abstract void onItemClick(AdapterView parent, View view, int position, long id); - - @Override - public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { - Intent intent = new Intent(getActivity(), TaskEditorActivity_.class); - intent.setAction(ACTION_EDIT); - intent.putExtra(DbTasksHelper.ID, (int) id); - startActivityForResult(intent, REQUEST_EDIT); - return true; - } - - @Override - public void onUpdate(Cursor... cursor) { - getActivity().runOnUiThread(() -> mAdapter.updateData(cursor)); - } - - @Override - public Fragment getInstance() { - return this; - } - - @Override - public TaskListView bindPresenter(TaskManagerPresenter presenter) { - this.mPresenter = presenter; - return this; - } - - @Override - public int getDataType() { - return mAdapter.getDataType(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - mPresenter.onResult(requestCode, resultCode, data); - } - - @Override - public void showAlert(String message) { - Snackbar.make(getActivity().getWindow().getDecorView(), message, 2000).show(); - } -} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListView.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListView.java deleted file mode 100644 index 8288e57..0000000 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListView.java +++ /dev/null @@ -1,17 +0,0 @@ -package ru.urfu.taskmanager.task_manager.fragments.view; - -import android.database.Cursor; -import android.support.v4.app.Fragment; - -import ru.urfu.taskmanager.task_manager.main.presenter.TaskManagerPresenter; -import ru.urfu.taskmanager.task_manager.models.OnDataUpdateListener; -import ru.urfu.taskmanager.utils.interfaces.Showable; - -public interface TaskListView extends OnDataUpdateListener, Showable -{ - TaskListView bindPresenter(TaskManagerPresenter presenter); - - int getDataType(); - - Fragment getInstance(); -} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/FiltersAdapter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/FiltersAdapter.java index a25b23d..922f826 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/FiltersAdapter.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/FiltersAdapter.java @@ -3,7 +3,7 @@ import android.widget.AdapterView; import android.widget.ListAdapter; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.DbTasksFilter; public interface FiltersAdapter extends ListAdapter, AdapterView.OnItemClickListener { diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/OnDataUpdateListener.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/OnDataUpdateListener.java new file mode 100644 index 0000000..154c500 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/OnDataUpdateListener.java @@ -0,0 +1,10 @@ +package ru.urfu.taskmanager.task_manager.main.adapters; + +import ru.urfu.taskmanager.data.db.DbFilter; + +public interface OnDataUpdateListener +{ + void onUpdate(T... data); + + void onUpdate(DbFilter filter); +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/SavedFiltersAdapter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/SavedFiltersAdapter.java index a463cb7..043f988 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/SavedFiltersAdapter.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/SavedFiltersAdapter.java @@ -15,7 +15,7 @@ import ru.urfu.taskmanager.R; import ru.urfu.taskmanager.task_manager.main.filter.FiltersStorage; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.DbTasksFilter; public class SavedFiltersAdapter extends BaseAdapter implements FiltersAdapter diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/ViewPagerAdapter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/ViewPagerAdapter.java index cd6201c..142f436 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/ViewPagerAdapter.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/adapters/ViewPagerAdapter.java @@ -7,7 +7,7 @@ import java.util.ArrayList; import java.util.List; -import ru.urfu.taskmanager.task_manager.fragments.view.TaskListView; +import ru.urfu.taskmanager.task_manager.main.fragments.view.TaskListView; public class ViewPagerAdapter extends FragmentStatePagerAdapter diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FilterLayoutWrapper.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FilterLayoutWrapper.java index 1945d2a..b8b73e7 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FilterLayoutWrapper.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FilterLayoutWrapper.java @@ -4,7 +4,7 @@ import android.view.View; import ru.urfu.taskmanager.task_manager.main.adapters.FiltersAdapter; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.DbTasksFilter; public class FilterLayoutWrapper { diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FilterViewHolder.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FilterViewHolder.java index f8ac676..fb64b82 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FilterViewHolder.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FilterViewHolder.java @@ -15,8 +15,8 @@ import ru.urfu.taskmanager.R; import ru.urfu.taskmanager.color_picker.recent.RecentColors; -import ru.urfu.taskmanager.utils.db.DbTasksHelper; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.DbTasksHelper; +import ru.urfu.taskmanager.data.db.DbTasksFilter; import ru.urfu.taskmanager.utils.tools.TimeUtils; @@ -123,6 +123,9 @@ DbTasksFilter.Builder compileFilterBuilder() { case 2: builder.sortBy(DbTasksHelper.TIME_EDITED); break; + case 3: + builder.sortBy(DbTasksHelper.ORDER); + break; } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FiltersStorage.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FiltersStorage.java index 65e1f46..e1b07fd 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FiltersStorage.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/filter/FiltersStorage.java @@ -8,7 +8,7 @@ import java.util.HashMap; import java.util.Map; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.DbTasksFilter; import ru.urfu.taskmanager.utils.tools.JSONFactory; public final class FiltersStorage diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/TaskPagerFragment.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/TaskPagerFragment.java new file mode 100644 index 0000000..86af0e5 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/TaskPagerFragment.java @@ -0,0 +1,74 @@ +package ru.urfu.taskmanager.task_manager.main.fragments; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.task_manager.main.fragments.view.TaskListActive; +import ru.urfu.taskmanager.task_manager.main.fragments.view.TaskListCompleted; +import ru.urfu.taskmanager.task_manager.main.view.TaskManager; +import ru.urfu.taskmanager.task_manager.main.fragments.adapters.TaskPagerAdapter; + +public class TaskPagerFragment extends Fragment implements View.OnClickListener +{ + protected TaskManager mManager; + protected FragmentStatePagerAdapter mPagerAdapter; + + protected ViewPager mViewPager; + protected TabLayout mTabLayout; + + protected FloatingActionButton fab; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return initView(inflater.inflate(R.layout.main_fragment, container, false)); + } + + private View initView(View view) { + mViewPager = (ViewPager) view.findViewById(R.id.viewpager); + mTabLayout = (TabLayout) view.findViewById(R.id.tablayout); + fab = (FloatingActionButton) view.findViewById(R.id.fab); + fab.setOnClickListener(this); + + return view; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + mManager = (TaskManager) getActivity(); + mPagerAdapter = getPagerAdapter(); + configViewPager(); + mTabLayout.setupWithViewPager(mViewPager); + } + + protected void configViewPager() { + mViewPager.setOffscreenPageLimit(2); + mViewPager.setAdapter(mPagerAdapter); + } + + protected FragmentStatePagerAdapter getPagerAdapter() { + return new TaskPagerAdapter(getChildFragmentManager()) + .addPage(TaskListActive.newInstance(getString(R.string.active_tasks_title))) + .addPage(TaskListCompleted.newInstance(getString(R.string.completed_tasks_title))); + } + + public static Fragment newInstance(Bundle args) { + TaskPagerFragment fragment = new TaskPagerFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onClick(View v) { + mManager.startEditor(null, null, null); + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/adapters/AbstractTaskListAdapter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/adapters/AbstractTaskListAdapter.java new file mode 100644 index 0000000..1fff116 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/adapters/AbstractTaskListAdapter.java @@ -0,0 +1,188 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.adapters; + +import android.content.Context; +import android.database.Cursor; +import android.database.DataSetObserver; +import android.support.v7.widget.RecyclerView; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.data.db.DbTasksHelper; +import ru.urfu.taskmanager.task_manager.main.fragments.helper.CursorProvider; + + +public abstract class AbstractTaskListAdapter extends RecyclerView.Adapter + implements CursorProvider +{ + protected static final String OVERDUE = "Просрочено"; + + protected static final int LAYOUT = R.layout.task_list_item; + + protected static final String[] FROM = new String[]{ + DbTasksHelper.TITLE, + DbTasksHelper.DESCRIPTION, + DbTasksHelper.TTL, + DbTasksHelper.DECORATE_COLOR, + }; + + protected static final int[] TO = new int[]{ + R.id.task_item_title, + R.id.task_item_description, + R.id.task_item_deadline, + R.id.task_item_color + }; + + protected static final String[] ACTIVE_DAYS = new String[]{ + "Сегодня", "Завтра", "Послезавтра" + }; + + protected static final String[] COMPLETED_DAYS = new String[]{ + "Сегодня", "Вчера", "Позавчера" + }; + + private List mMovedPositions; + + private Context mContext; + + private Cursor mCursor; + + private boolean mDataValid; + + private int mRowIdColumn; + + private DataSetObserver mDataSetObserver; + + public AbstractTaskListAdapter(Context context, Cursor cursor) { + mContext = context; + mCursor = cursor; + mDataValid = cursor != null; + mRowIdColumn = mDataValid ? mCursor.getColumnIndex("_id") : -1; + mDataSetObserver = new NotifyingDataSetObserver(); + if (mCursor != null) { + mCursor.registerDataSetObserver(mDataSetObserver); + } + } + + @Override + public void onItemDismiss(int position) {} + + @Override + public boolean onItemMove(int fromPosition, int toPosition) { + swapPositions(fromPosition, toPosition); + notifyItemMoved(fromPosition, toPosition); + return true; + } + + public Cursor getCursor() { + return mCursor; + } + + @Override + public int getItemCount() { + if (mDataValid && mCursor != null) { + return mCursor.getCount(); + } + return 0; + } + + @Override + public long getItemId(int position) { + if (mDataValid && mCursor != null && mCursor.moveToPosition(position)) { + return mCursor.getLong(mRowIdColumn); + } + return 0; + } + + @Override + public void setHasStableIds(boolean hasStableIds) { + super.setHasStableIds(true); + } + + public abstract void onBindViewHolder(VH viewHolder, Cursor cursor); + + @Override + public void onBindViewHolder(VH viewHolder, int position) { + if (!mDataValid) { + throw new IllegalStateException("this should only be called when the cursor is valid"); + } + if (!mCursor.moveToPosition(position)) { + throw new IllegalStateException("couldn't move cursor to position " + position); + } + onBindViewHolder(viewHolder, mCursor); + } + + /** + * Change the underlying cursor to a new cursor. If there is an existing cursor it will be + * closed. + */ + public void changeCursor(Cursor cursor) { + Cursor old = swapCursor(cursor); + if (old != null) { + old.close(); + } + } + + /** + * Swap in a new Cursor, returning the old Cursor. Unlike + * {@link #changeCursor(Cursor)}, the returned old Cursor is not + * closed. + */ + public Cursor swapCursor(Cursor newCursor) { + if (newCursor == mCursor) { + return null; + } + final Cursor oldCursor = mCursor; + if (oldCursor != null && mDataSetObserver != null) { + oldCursor.unregisterDataSetObserver(mDataSetObserver); + } + mCursor = newCursor; + if (mCursor != null) { + if (mDataSetObserver != null) { + mCursor.registerDataSetObserver(mDataSetObserver); + } + mRowIdColumn = newCursor.getColumnIndexOrThrow("_id"); + mDataValid = true; + notifyDataSetChanged(); + } else { + mRowIdColumn = -1; + mDataValid = false; + notifyDataSetChanged(); + //There is no notifyDataSetInvalidated() method in RecyclerView.Adapter + } + + mMovedPositions = new LinkedList<>(); + for (int i = 0; i < newCursor.getCount(); i++) { + mMovedPositions.add(i); + } + + return oldCursor; + } + + public void swapPositions(int from, int to) { + Collections.swap(mMovedPositions, from, to); + } + + public int getMovedPosition(int oldPosition) { + return mMovedPositions.get(oldPosition); + } + + private class NotifyingDataSetObserver extends DataSetObserver { + @Override + public void onChanged() { + super.onChanged(); + mDataValid = true; + notifyDataSetChanged(); + } + + @Override + public void onInvalidated() { + super.onInvalidated(); + mDataValid = false; + notifyDataSetChanged(); + //There is no notifyDataSetInvalidated() method in RecyclerView.Adapter + } + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/adapters/TaskPagerAdapter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/adapters/TaskPagerAdapter.java new file mode 100644 index 0000000..e150cb4 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/adapters/TaskPagerAdapter.java @@ -0,0 +1,40 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.adapters; + +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; + +import java.util.ArrayList; +import java.util.List; + +import ru.urfu.taskmanager.task_manager.main.fragments.view.TaskListFragment; + +public class TaskPagerAdapter extends FragmentStatePagerAdapter +{ + private List fragments; + + public TaskPagerAdapter(FragmentManager fm) { + super(fm); + this.fragments = new ArrayList<>(); + } + + public TaskPagerAdapter addPage(TaskListFragment fragment) { + fragments.add(fragment); + return this; + } + + @Override + public Fragment getItem(int position) { + return fragments.get(position); + } + + @Override + public CharSequence getPageTitle(int position) { + return fragments.get(position).getTitle(); + } + + @Override + public int getCount() { + return fragments.size(); + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/adapters/TasksListAdapter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/adapters/TasksListAdapter.java new file mode 100644 index 0000000..7151b25 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/adapters/TasksListAdapter.java @@ -0,0 +1,207 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.adapters; + +import android.content.Context; +import android.database.Cursor; +import android.graphics.drawable.GradientDrawable; +import android.support.v4.view.MotionEventCompat; +import android.support.v4.view.ViewCompat; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import java.util.Calendar; + +import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.data.db.DbFilter; +import ru.urfu.taskmanager.data.db.DbTasks; +import ru.urfu.taskmanager.data.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.SimpleDatabase; +import ru.urfu.taskmanager.task_manager.main.fragments.helper.ItemTouchHelperViewHolder; +import ru.urfu.taskmanager.task_manager.main.fragments.view.TaskListFragment; +import ru.urfu.taskmanager.task_manager.models.TaskEntry; +import ru.urfu.taskmanager.utils.tools.TimeUtils; + +public class TasksListAdapter extends AbstractTaskListAdapter +{ + private final TaskListFragment mFragment; + private final SimpleDatabase mDatabase; + + private DbFilter mDefaultFilter; + + public TasksListAdapter(TaskListFragment fragment, DbTasksFilter filter) { + super(fragment.getContext(), null); + this.mFragment = fragment; + this.mDefaultFilter = filter; + this.mDatabase = DbTasks.getInstance(); + updateData(mDatabase.getCursor(mDefaultFilter)); + } + + @Override + public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) { + TaskEntry entry = mDatabase.getCurrentEntryFromCursor(cursor); + TaskEntry prev = (cursor.moveToPrevious()) + ? mDatabase.getCurrentEntryFromCursor(cursor) + : null; + + GradientDrawable gd = new GradientDrawable(); + gd.setColor(entry.getColorInt()); + gd.setCornerRadius(100f); + + viewHolder.title.setText(entry.getTitle()); + viewHolder.description.setText(entry.getDescription()); + viewHolder.ttl.setText(TimeUtils.getHoursAndMinutesFromUnix(entry.getTtlTimestamp()).toString()); + viewHolder.ttl.setBackground(gd); + + ViewCompat.setTransitionName(viewHolder.ttl, String.valueOf(cursor.getPosition()) + mDefaultFilter.getType()); + attachHeader(viewHolder, entry, prev); + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + LayoutInflater inflater = (LayoutInflater) parent.getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + return new ViewHolder(inflater.inflate(LAYOUT, parent, false)); + } + + private ViewHolder attachHeader(ViewHolder holder, TaskEntry entry, TaskEntry prev) { + String entryTitle = getTitleFromEntry(entry); + + if (entryTitle.equals(OVERDUE)) + holder.layout.setAlpha(0.4f); + else holder.layout.setAlpha(1f); + + if (mDefaultFilter.isOrdered()) { + holder.header_text.setText(entryTitle); + holder.header.setVisibility(View.VISIBLE); + return holder; + } + + if (prev != null) { + String prevTitle = getTitleFromEntry(prev); + + if (!entryTitle.equals(prevTitle)) { + holder.header_text.setText(entryTitle); + holder.header.setVisibility(View.VISIBLE); + } else { + holder.header.setVisibility(View.GONE); + } + } else { + holder.header_text.setText(entryTitle); + holder.header.setVisibility(View.VISIBLE); + } + + return holder; + } + + private String getTitleFromEntry(TaskEntry entry) { + if (System.currentTimeMillis() > entry.getTtlTimestamp() & mDefaultFilter.getType() == DbTasksFilter.ACTIVE_TASK) { + return OVERDUE; + } else { + Calendar entryDate = Calendar.getInstance(); + entryDate.setTimeInMillis(entry.getTtlTimestamp()); + int diffDay = Math.abs(entryDate.get(Calendar.DAY_OF_YEAR) - Calendar.getInstance().get(Calendar.DAY_OF_YEAR)); + return getHeaderTitleByNum(diffDay, entryDate); + } + } + + private String getHeaderTitleByNum(int num, Calendar entryDate) { + if (num < 3) { + switch (mDefaultFilter.getType()) { + case DbTasksFilter.ACTIVE_TASK: + return ACTIVE_DAYS[num]; + case DbTasksFilter.COMPLETED_TASK: + return COMPLETED_DAYS[num]; + } + } + + return TimeUtils.format(entryDate); + } + + public void updateData(Cursor... cursor) { + if (cursor.length == 0) { + updateCursor(mDatabase.getCursor(mDefaultFilter)); + } else { + updateCursor(cursor[0]); + } + } + + public void updateFilter(DbFilter filter) { + mDefaultFilter = filter; + } + + private void updateCursor(Cursor cursor) { + changeCursor(cursor); + } + + public int getDataType() { + return mDefaultFilter.getType(); + } + + private void updateOrders() { + mDatabase.startTransaction(aVoid -> { + for (int position = 0; position < getItemCount(); position++) { + TaskEntry current = mDatabase.getEntryById((int) getItemId(getMovedPosition(position))); + current.setOrder(position); + mDatabase.updateEntry(current); + } + }); + } + + public class ViewHolder extends RecyclerView.ViewHolder + implements View.OnClickListener, View.OnLongClickListener, ItemTouchHelperViewHolder + { + + public View layout; + public View header; + public TextView header_text; + public TextView title; + public TextView description; + public TextView ttl; + + public ViewHolder(View view) { + super(view); + this.layout = view.findViewById(R.id.task_layout); + this.header = view.findViewById(R.id.task_header); + this.header_text = (TextView) view.findViewById(R.id.header_text); + this.title = (TextView) view.findViewById(R.id.task_item_title); + this.description = (TextView) view.findViewById(R.id.task_item_description); + this.ttl = (TextView) view.findViewById(R.id.task_item_deadline); + + layout.setOnClickListener(this); + layout.setOnLongClickListener(this); + + layout.setOnTouchListener((v, event) -> { + if (mDefaultFilter.isOrdered()) { + if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { + mFragment.onStartDrag(ViewHolder.this); + } + } + + return false; + }); + } + + @Override + public void onClick(View v) { + mFragment.onItemClick(this, getAdapterPosition(), TasksListAdapter.this.getItemId(getAdapterPosition())); + } + + @Override + public boolean onLongClick(View v) { + mFragment.onItemLongClick(this, getAdapterPosition(), TasksListAdapter.this.getItemId(getAdapterPosition())); + return true; + } + + @Override + public void onItemSelected() {} + + @Override + public void onItemClear() { + updateOrders(); + } + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/CursorProvider.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/CursorProvider.java new file mode 100644 index 0000000..af0c027 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/CursorProvider.java @@ -0,0 +1,10 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.helper; + +import android.database.Cursor; + +import ru.urfu.taskmanager.task_manager.main.fragments.helper.ItemTouchHelperAdapter; + +public interface CursorProvider extends ItemTouchHelperAdapter +{ + Cursor getCursor(); +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/ItemTouchHelperAdapter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/ItemTouchHelperAdapter.java new file mode 100644 index 0000000..6b7413c --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/ItemTouchHelperAdapter.java @@ -0,0 +1,8 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.helper; + +public interface ItemTouchHelperAdapter { + + boolean onItemMove(int fromPosition, int toPosition); + + void onItemDismiss(int position); +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/ItemTouchHelperViewHolder.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/ItemTouchHelperViewHolder.java new file mode 100644 index 0000000..6853a72 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/ItemTouchHelperViewHolder.java @@ -0,0 +1,8 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.helper; + +public interface ItemTouchHelperViewHolder { + + void onItemSelected(); + + void onItemClear(); +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/OnStartDragListener.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/OnStartDragListener.java new file mode 100644 index 0000000..f2b09dd --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/OnStartDragListener.java @@ -0,0 +1,7 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.helper; + +import android.support.v7.widget.RecyclerView; + +public interface OnStartDragListener { + void onStartDrag(RecyclerView.ViewHolder viewHolder); +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/SimpleItemTouchHelperCallback.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/SimpleItemTouchHelperCallback.java new file mode 100644 index 0000000..5b29eed --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/helper/SimpleItemTouchHelperCallback.java @@ -0,0 +1,90 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.helper; + +import android.graphics.Canvas; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; + +public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { + + public static final float ALPHA_FULL = 1.0f; + + private final ItemTouchHelperAdapter mAdapter; + + public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { + mAdapter = adapter; + } + + @Override + public boolean isLongPressDragEnabled() { + return true; + } + + @Override + public boolean isItemViewSwipeEnabled() { + return false; + } + + @Override + public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + if (recyclerView.getLayoutManager() instanceof GridLayoutManager) { + final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; + final int swipeFlags = 0; + return makeMovementFlags(dragFlags, swipeFlags); + } else { + final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; + final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; + return makeMovementFlags(dragFlags, swipeFlags); + } + } + + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { + if (source.getItemViewType() != target.getItemViewType()) { + return false; + } + + mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition()); + return true; + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) { + mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); + } + + @Override + public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { + final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth(); + viewHolder.itemView.setAlpha(alpha); + viewHolder.itemView.setTranslationX(dX); + } else { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + } + } + + @Override + public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { + if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { + if (viewHolder instanceof ItemTouchHelperViewHolder) { + ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder; + itemViewHolder.onItemSelected(); + } + } + + super.onSelectedChanged(viewHolder, actionState); + } + + @Override + public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + + viewHolder.itemView.setAlpha(ALPHA_FULL); + + if (viewHolder instanceof ItemTouchHelperViewHolder) { + ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder; + itemViewHolder.onItemClear(); + } + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/CustomTransition.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/CustomTransition.java new file mode 100644 index 0000000..83d79b8 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/CustomTransition.java @@ -0,0 +1,28 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.view; + +import android.annotation.TargetApi; +import android.content.Context; +import android.os.Build; +import android.transition.ChangeImageTransform; +import android.transition.ChangeTransform; +import android.util.AttributeSet; + +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +public class CustomTransition extends android.transition.TransitionSet +{ + public CustomTransition() { + init(); + } + + public CustomTransition(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + setOrdering(ORDERING_TOGETHER); + addTransition(new android.transition.ChangeBounds()). + addTransition(new ChangeTransform()). + addTransition(new ChangeImageTransform()); + } +} \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListActive.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListActive.java similarity index 56% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListActive.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListActive.java index 93814d1..def71ad 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListActive.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListActive.java @@ -1,47 +1,57 @@ -package ru.urfu.taskmanager.task_manager.fragments.view; +package ru.urfu.taskmanager.task_manager.main.fragments.view; +import android.os.Bundle; import android.support.v7.widget.PopupMenu; import android.view.Gravity; -import android.view.View; -import android.widget.AdapterView; import com.github.florent37.singledateandtimepicker.dialog.SingleDateAndTimePickerDialog; import java.util.Date; import ru.urfu.taskmanager.R; -import ru.urfu.taskmanager.task_manager.fragments.adapters.TasksListAdapter; -import ru.urfu.taskmanager.utils.db.DbTasksHelper; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; +import ru.urfu.taskmanager.task_manager.main.fragments.adapters.TasksListAdapter; +import ru.urfu.taskmanager.data.db.DbTasksHelper; +import ru.urfu.taskmanager.data.db.DbTasksFilter; public class TaskListActive extends TaskListFragment { + private DbTasksFilter filter; + + public static TaskListActive newInstance(String title) { + Bundle args = new Bundle(); + args.putString(ARG_TITLE_KEY, title); + + TaskListActive fragment = new TaskListActive(); + fragment.setArguments(args); + return fragment; + } + @Override protected TasksListAdapter getAdapter() { - return new TasksListAdapter(getContext(), - DbTasksFilter.builder() - .setType(DbTasksFilter.ACTIVE_TASK) - .sortBy(DbTasksHelper.TTL) - .build() - ); + mManager.getFilterLayoutWrapper().onCompileFilter(builder -> filter = builder.setType(DbTasksFilter.ACTIVE_TASK) + .sortBy(DbTasksHelper.TTL) + .build()); + + return new TasksListAdapter(this, filter); } @SuppressWarnings("deprecation") @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - PopupMenu popup = new PopupMenu(getContext(), view); + public void onItemClick(TasksListAdapter.ViewHolder holder, int position, long id) { + PopupMenu popup = new PopupMenu(getContext(), holder.layout); popup.getMenuInflater().inflate(R.menu.active_task_option_menu, popup.getMenu()); + popup.setGravity(Gravity.END); popup.setOnMenuItemClickListener(item -> { switch (item.getItemId()) { case R.id.task_is_complete: - mPresenter.taskIsCompleted((int) id); + mManager.getPresenter().taskIsCompleted((int) id); break; case R.id.edit_the_task: - mPresenter.editTheTask((int) id); + mManager.getPresenter().editTheTask(position, mAdapter, holder); break; case R.id.postpone_the_task: { - mPresenter.postponeTheTask( + mManager.getPresenter().postponeTheTask( (int) id, (date, entry) -> new SingleDateAndTimePickerDialog.Builder(getContext()) .mainColor(getResources().getColor(R.color.colorAccent)) @@ -55,13 +65,12 @@ public void onItemClick(AdapterView parent, View view, int position, long id) } break; case R.id.delete_the_task: - mPresenter.deleteTheTask((int) id); + mManager.getPresenter().deleteTheTask((int) id); break; } return true; }); - popup.setGravity(Gravity.END); popup.show(); } } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListCompleted.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListCompleted.java similarity index 58% rename from Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListCompleted.java rename to Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListCompleted.java index 5e9195f..47dd2cf 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/fragments/view/TaskListCompleted.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListCompleted.java @@ -1,41 +1,50 @@ -package ru.urfu.taskmanager.task_manager.fragments.view; +package ru.urfu.taskmanager.task_manager.main.fragments.view; +import android.os.Bundle; import android.support.v7.widget.PopupMenu; import android.view.Gravity; -import android.view.View; -import android.widget.AdapterView; import com.github.florent37.singledateandtimepicker.dialog.SingleDateAndTimePickerDialog; import java.util.Date; import ru.urfu.taskmanager.R; -import ru.urfu.taskmanager.task_manager.fragments.adapters.TasksListAdapter; -import ru.urfu.taskmanager.utils.db.DbTasksHelper; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.DbTasksHelper; +import ru.urfu.taskmanager.task_manager.main.fragments.adapters.TasksListAdapter; public class TaskListCompleted extends TaskListFragment { + private DbTasksFilter filter; + + public static TaskListCompleted newInstance(String title) { + Bundle args = new Bundle(); + args.putString(ARG_TITLE_KEY, title); + + TaskListCompleted fragment = new TaskListCompleted(); + fragment.setArguments(args); + return fragment; + } + @Override protected TasksListAdapter getAdapter() { - return new TasksListAdapter(getContext(), - DbTasksFilter.builder() - .setType(DbTasksFilter.COMPLETED_TASK) - .sortBy(DbTasksHelper.TTL) - .build() - ); + mManager.getFilterLayoutWrapper().onCompileFilter(builder -> filter = builder.setType(DbTasksFilter.COMPLETED_TASK) + .sortBy(DbTasksHelper.TTL) + .build()); + + return new TasksListAdapter(this, filter); } @SuppressWarnings("deprecation") @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - PopupMenu popup = new PopupMenu(getContext(), view); + public void onItemClick(TasksListAdapter.ViewHolder holder, int position, long id) { + PopupMenu popup = new PopupMenu(getContext(), holder.layout); popup.getMenuInflater().inflate(R.menu.completed_task_option_menu, popup.getMenu()); popup.setOnMenuItemClickListener(item -> { switch (item.getItemId()) { case R.id.restore_the_task: { - mPresenter.restoreTheTask( + mManager.getPresenter().restoreTheTask( (int) id, (date, entry) -> new SingleDateAndTimePickerDialog.Builder(getContext()) .mainColor(getResources().getColor(R.color.colorAccent)) diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListFragment.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListFragment.java new file mode 100644 index 0000000..2443040 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListFragment.java @@ -0,0 +1,105 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.view; + +import android.database.Cursor; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; +import android.support.v4.app.Fragment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import ru.urfu.taskmanager.R; +import ru.urfu.taskmanager.data.db.DbFilter; +import ru.urfu.taskmanager.task_manager.main.fragments.adapters.TasksListAdapter; +import ru.urfu.taskmanager.task_manager.main.fragments.helper.OnStartDragListener; +import ru.urfu.taskmanager.task_manager.main.fragments.helper.SimpleItemTouchHelperCallback; +import ru.urfu.taskmanager.task_manager.main.view.TaskManager; + +public abstract class TaskListFragment extends Fragment + implements TaskListView, OnStartDragListener +{ + public static final String ARG_TITLE_KEY = "ru.urfu.taskmanager.task_manager.ARG_TITLE_KEY"; + private ItemTouchHelper mItemTouchHelper; + protected TaskManager mManager; + + RecyclerView mTaskListView; + TasksListAdapter mAdapter; + + @Override + public String getTitle() { + return getArguments().getString(ARG_TITLE_KEY); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.active_tasks_fragment, container, false); + return initView(view); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + mManager = (TaskManager) getActivity(); + mManager.getPresenter().bindView(this); + + mTaskListView.setLayoutManager(new LinearLayoutManager(getContext())); + mTaskListView.setAdapter(mAdapter = getAdapter()); + + ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(mAdapter); + mItemTouchHelper = new ItemTouchHelper(callback); + mItemTouchHelper.attachToRecyclerView(mTaskListView); + } + + protected View initView(View root) { + mTaskListView = (RecyclerView) root.findViewById(R.id.task_list); + return root; + } + + protected abstract TasksListAdapter getAdapter(); + + public abstract void onItemClick(TasksListAdapter.ViewHolder holder, int position, long id); + + public boolean onItemLongClick(TasksListAdapter.ViewHolder holder, int position, long id) { + mManager.startEditor(position, mAdapter, holder); + return true; + } + + @Override + public void onUpdate(Cursor... cursor) { + getActivity().runOnUiThread(() -> mAdapter.updateData(cursor)); + } + + @Override + public void onUpdate(DbFilter filter) { + getActivity().runOnUiThread(() -> mAdapter.updateFilter(filter)); + } + + @Override + public Fragment getInstance() { + return this; + } + + @Override + public int getDataType() { + return mAdapter.getDataType(); + } + + @Override + public void showAlert(String message) { + Snackbar.make(getActivity().getWindow().getDecorView(), message, 2000).show(); + } + + @Override + public void onStartDrag(RecyclerView.ViewHolder viewHolder) { + mItemTouchHelper.startDrag(viewHolder); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mManager.getPresenter().unBindView(this); + } +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListView.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListView.java new file mode 100644 index 0000000..ca1da86 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/fragments/view/TaskListView.java @@ -0,0 +1,16 @@ +package ru.urfu.taskmanager.task_manager.main.fragments.view; + +import android.database.Cursor; +import android.support.v4.app.Fragment; + +import ru.urfu.taskmanager.task_manager.main.adapters.OnDataUpdateListener; +import ru.urfu.taskmanager.utils.interfaces.Showable; + +public interface TaskListView extends OnDataUpdateListener, Showable +{ + String getTitle(); + + int getDataType(); + + Fragment getInstance(); +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/presenter/TaskManagerPresenter.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/presenter/TaskManagerPresenter.java index d21b947..1038045 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/presenter/TaskManagerPresenter.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/presenter/TaskManagerPresenter.java @@ -1,13 +1,14 @@ package ru.urfu.taskmanager.task_manager.main.presenter; -import android.content.Intent; import android.net.Uri; import java.util.Date; -import ru.urfu.taskmanager.task_manager.fragments.view.TaskListView; +import ru.urfu.taskmanager.data.db.DbTasksFilter; +import ru.urfu.taskmanager.task_manager.main.fragments.helper.CursorProvider; +import ru.urfu.taskmanager.task_manager.main.fragments.adapters.TasksListAdapter; +import ru.urfu.taskmanager.task_manager.main.fragments.view.TaskListView; import ru.urfu.taskmanager.task_manager.models.TaskEntry; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; import ru.urfu.taskmanager.utils.interfaces.Callback; import ru.urfu.taskmanager.utils.interfaces.Coupler; @@ -15,6 +16,8 @@ public interface TaskManagerPresenter { TaskListView bindView(TaskListView view); + TaskListView unBindView(TaskListView view); + void taskIsCompleted(int id); void postponeTheTask(int id, Coupler, TaskEntry> coupler); @@ -23,7 +26,7 @@ public interface TaskManagerPresenter void restoreTheTask(int id, Coupler, TaskEntry> coupler); - void editTheTask(int id); + void editTheTask(int id, CursorProvider adapter, TasksListAdapter.ViewHolder holder); void applyFilter(DbTasksFilter.Builder filterBuilder); @@ -31,7 +34,9 @@ public interface TaskManagerPresenter void exportData(String path); - void onResult(int requestCode, int resultCode, Intent data); + void importData(Uri path); + + void onResult(int requestCode); void onDestroy(); } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/presenter/TaskManagerPresenterImpl.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/presenter/TaskManagerPresenterImpl.java index 9dbef8e..fd1e62e 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/presenter/TaskManagerPresenterImpl.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/presenter/TaskManagerPresenterImpl.java @@ -1,10 +1,8 @@ package ru.urfu.taskmanager.task_manager.main.presenter; -import android.content.Intent; import android.database.Cursor; import android.net.Uri; -import java.io.File; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.ArrayList; @@ -13,49 +11,55 @@ import java.util.concurrent.atomic.AtomicInteger; import ru.urfu.taskmanager.R; -import ru.urfu.taskmanager.task_manager.fragments.view.TaskListView; -import ru.urfu.taskmanager.task_manager.main.tools.DataExportController; -import ru.urfu.taskmanager.task_manager.main.tools.DataImportController; -import ru.urfu.taskmanager.task_manager.main.tools.BackupManager; +import ru.urfu.taskmanager.auth.models.User; +import ru.urfu.taskmanager.data.backup.BackupManager; +import ru.urfu.taskmanager.data.backup.DataExportController; +import ru.urfu.taskmanager.data.backup.DataImportController; +import ru.urfu.taskmanager.data.backup.TasksGenerator; +import ru.urfu.taskmanager.data.db.DbFilter; +import ru.urfu.taskmanager.data.db.DbTasks; +import ru.urfu.taskmanager.data.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.async.DbAsyncExecutor; +import ru.urfu.taskmanager.data.db.async.ExecuteControllerAdapter; +import ru.urfu.taskmanager.data.network.APIServiceExecutor; +import ru.urfu.taskmanager.task_manager.main.fragments.helper.CursorProvider; +import ru.urfu.taskmanager.task_manager.main.fragments.adapters.TasksListAdapter; +import ru.urfu.taskmanager.task_manager.main.fragments.view.TaskListView; import ru.urfu.taskmanager.task_manager.main.view.TaskManager; -import ru.urfu.taskmanager.task_manager.main.tools.TasksGenerator; import ru.urfu.taskmanager.task_manager.models.TaskEntry; -import ru.urfu.taskmanager.utils.db.async.DbAsyncExecutor; -import ru.urfu.taskmanager.utils.db.DbFilter; -import ru.urfu.taskmanager.utils.db.DbTasks; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; -import ru.urfu.taskmanager.utils.db.async.ExecuteControllerAdapter; import ru.urfu.taskmanager.utils.interfaces.Callback; import ru.urfu.taskmanager.utils.interfaces.Coupler; -import static android.app.Activity.RESULT_OK; import static ru.urfu.taskmanager.task_manager.main.view.TaskManagerActivity.REQUEST_CREATE; import static ru.urfu.taskmanager.task_manager.main.view.TaskManagerActivity.REQUEST_EDIT; -import static ru.urfu.taskmanager.task_manager.main.view.TaskManagerActivity.REQUEST_IMPORT; public class TaskManagerPresenterImpl implements TaskManagerPresenter { private static final String EXPORTED_FILENAME = "itemlist.ili"; private final TaskManager mManager; - private final DbAsyncExecutor dbAsyncExecutor; + private final APIServiceExecutor mAPIServiceExecutor; + private final DbAsyncExecutor mDbAsyncExecutor; private final BackupManager mDataExporter; private final List mTasksList; public TaskManagerPresenterImpl(TaskManager view) { this.mManager = view; this.mTasksList = new ArrayList<>(); - this.dbAsyncExecutor = DbTasks.getInstance().getAsyncExecutor(); + this.mAPIServiceExecutor = User.getActiveUser().getExecutor(); this.mDataExporter = new BackupManager(); + this.mDbAsyncExecutor = DbTasks.getInstance().getAsyncExecutor(); } @Override public void taskIsCompleted(int id) { + long timestamp = System.currentTimeMillis(); + TaskEntry updatedEntry = new TaskEntry(id) - .setTtl(System.currentTimeMillis()) - .setCompleted(true); + .setTtl(timestamp) + .setEdited(timestamp); - dbAsyncExecutor.updateEntry(updatedEntry, new ExecuteControllerAdapter() { + mAPIServiceExecutor.updateEntry(updatedEntry, new ExecuteControllerAdapter() { @Override public void onFinish() { notifyDataUpdate(); @@ -65,25 +69,28 @@ public void onFinish() { @Override public void postponeTheTask(int id, Coupler, TaskEntry> coupler) { - dbAsyncExecutor.getEntryById(id, new ExecuteControllerAdapter() { + mDbAsyncExecutor.getEntryById(id, new ExecuteControllerAdapter() + { @Override public void onFinish(TaskEntry entry) { - coupler.bind(date -> { - entry.setTtl(date.getTime()); - dbAsyncExecutor.updateEntry(entry, new ExecuteControllerAdapter() { - @Override - public void onFinish() { - notifyDataUpdate(); + coupler.bind(date -> mAPIServiceExecutor.updateEntry( + entry.setTtl(date.getTime()) + .setEdited(System.currentTimeMillis()), + new ExecuteControllerAdapter() + { + @Override + public void onFinish() { + notifyDataUpdate(); + } } - }); - }, entry); + ), entry); } }); } @Override public void deleteTheTask(int id) { - dbAsyncExecutor.removeEntryById(id, new ExecuteControllerAdapter() { + mAPIServiceExecutor.removeEntryById(id, new ExecuteControllerAdapter() { @Override public void onFinish() { notifyDataUpdate(); @@ -93,13 +100,13 @@ public void onFinish() { @Override public void restoreTheTask(int id, Coupler, TaskEntry> coupler) { - dbAsyncExecutor.getEntryById(id, new ExecuteControllerAdapter() { + mDbAsyncExecutor.getEntryById(id, new ExecuteControllerAdapter() + { @Override public void onFinish(TaskEntry entry) { - entry.setCompleted(false); coupler.bind(date -> { - entry.setTtl(date.getTime()); - dbAsyncExecutor.updateEntry(entry, new ExecuteControllerAdapter() { + entry.setTtl(date.getTime()).setEdited(System.currentTimeMillis()); + mAPIServiceExecutor.updateEntry(entry, new ExecuteControllerAdapter() { @Override public void onFinish() { notifyDataUpdate(); @@ -111,8 +118,8 @@ public void onFinish() { } @Override - public void editTheTask(int id) { - mManager.startEditor(id); + public void editTheTask(int id, CursorProvider adapter, TasksListAdapter.ViewHolder holder) { + mManager.startEditor(id, adapter, holder); } @Override @@ -127,7 +134,7 @@ public void generateBigData() { @Override public void exportData(String path) { - dbAsyncExecutor.getAllEntries( + mAPIServiceExecutor.getAllEntries( new DataExportController<>( mManager.getBaseContext(), mManager, path, EXPORTED_FILENAME, @@ -136,43 +143,47 @@ public void exportData(String path) { ); } - private void importData(Uri uri) throws FileNotFoundException { - InputStream inputStream = mManager.getBaseContext() - .getContentResolver() - .openInputStream(uri); - - mDataExporter.importFrom(inputStream, TaskEntry.class, - new DataImportController<>(mManager, dbAsyncExecutor, aVoid -> notifyDataUpdate()) - ); + @Override + public void importData(Uri uri) { + InputStream inputStream; + + try { + inputStream = mManager.getBaseContext() + .getContentResolver() + .openInputStream(uri); + + mDataExporter.importFrom(inputStream, TaskEntry.class, + new DataImportController<>(mManager, mDbAsyncExecutor, aVoid -> mManager.syncData()) + ); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } } @Override public TaskListView bindView(TaskListView view) { mTasksList.add(view); - return view.bindPresenter(this); + return view; } @Override - public void onResult(int requestCode, int resultCode, Intent data) { - if (resultCode == RESULT_OK) { - switch (requestCode) { - case REQUEST_CREATE: - mManager.showAlert(mManager.getResources().getString(R.string.task_was_created)); - break; - case REQUEST_EDIT: - mManager.showAlert(mManager.getResources().getString(R.string.task_was_updated)); - break; - case REQUEST_IMPORT: - try { - importData(data.getData()); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - break; - } + public TaskListView unBindView(TaskListView view) { + mTasksList.remove(view); + return view; + } - notifyDataUpdate(); + @Override + public void onResult(int requestCode) { + switch (requestCode) { + case REQUEST_CREATE: + mManager.showAlert(mManager.getResources().getString(R.string.task_was_created)); + break; + case REQUEST_EDIT: + mManager.showAlert(mManager.getResources().getString(R.string.task_was_updated)); + break; } + + notifyDataUpdate(); } private void notifyDataUpdate() { @@ -190,7 +201,7 @@ private void notifyDataUpdate(DbTasksFilter.Builder builder) { .setType(taskList.getDataType()) .build(); - dbAsyncExecutor.getCursor(filter, new ExecuteControllerAdapter() { + mAPIServiceExecutor.getCursor(filter, new ExecuteControllerAdapter() { @Override public void onStart() { mManager.showProgress(); @@ -200,6 +211,7 @@ public void onStart() { @Override public void onFinish(Cursor cursor) { taskList.onUpdate(cursor); + taskList.onUpdate(filter); if (counter.decrementAndGet() == 0) mManager.hideProgress(); } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/view/TaskManager.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/view/TaskManager.java index dff7d30..ef8ad55 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/view/TaskManager.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/view/TaskManager.java @@ -1,10 +1,23 @@ package ru.urfu.taskmanager.task_manager.main.view; -import android.view.View; +import android.support.annotation.Nullable; +import android.support.v4.app.FragmentManager; +import ru.urfu.taskmanager.task_manager.main.fragments.helper.CursorProvider; +import ru.urfu.taskmanager.task_manager.main.fragments.adapters.TasksListAdapter; +import ru.urfu.taskmanager.task_manager.main.filter.FilterLayoutWrapper; +import ru.urfu.taskmanager.task_manager.main.presenter.TaskManagerPresenter; import ru.urfu.taskmanager.utils.interfaces.Progressive; -public interface TaskManager extends View.OnClickListener, Progressive +public interface TaskManager extends Progressive { - void startEditor(int id); + TaskManagerPresenter getPresenter(); + + FilterLayoutWrapper getFilterLayoutWrapper(); + + FragmentManager getSupportFragmentManager(); + + void syncData(); + + void startEditor(@Nullable Integer position, CursorProvider adapter, TasksListAdapter.ViewHolder viewHolder); } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/view/TaskManagerActivity.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/view/TaskManagerActivity.java index 7540e30..f1ef3cd 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/view/TaskManagerActivity.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/main/view/TaskManagerActivity.java @@ -2,22 +2,32 @@ import android.Manifest; import android.app.ProgressDialog; +import android.content.BroadcastReceiver; import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Configuration; +import android.net.ConnectivityManager; +import android.os.Build; import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.NavigationView; import android.support.design.widget.Snackbar; -import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; import android.support.v4.view.MenuItemCompat; -import android.support.v4.view.ViewPager; +import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; import android.support.v7.widget.Toolbar; import android.text.InputType; +import android.transition.Fade; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AutoCompleteTextView; import android.widget.EditText; +import android.widget.FrameLayout; import android.widget.ProgressBar; import android.widget.Spinner; import android.widget.TextView; @@ -28,6 +38,7 @@ import com.karumi.dexter.Dexter; import com.karumi.dexter.MultiplePermissionsReport; +import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.UiThread; import org.androidannotations.annotations.ViewById; @@ -35,28 +46,33 @@ import java.lang.reflect.Field; import ru.urfu.taskmanager.R; -import ru.urfu.taskmanager.task_manager.fragments.view.TaskListActive; -import ru.urfu.taskmanager.task_manager.fragments.view.TaskListCompleted; +import ru.urfu.taskmanager.auth.models.User; +import ru.urfu.taskmanager.data.db.DbTasksFilter; +import ru.urfu.taskmanager.data.db.DbTasksHelper; +import ru.urfu.taskmanager.data.network.sync_module.BroadcastSyncManager; +import ru.urfu.taskmanager.task_manager.editor.view.EditorPagerFragment; +import ru.urfu.taskmanager.task_manager.editor.view.TaskEditorFragment; +import ru.urfu.taskmanager.task_manager.main.fragments.TaskPagerFragment; +import ru.urfu.taskmanager.task_manager.main.fragments.helper.CursorProvider; +import ru.urfu.taskmanager.task_manager.main.fragments.adapters.TasksListAdapter; +import ru.urfu.taskmanager.task_manager.main.fragments.view.CustomTransition; import ru.urfu.taskmanager.task_manager.main.adapters.FiltersAdapter; import ru.urfu.taskmanager.task_manager.main.adapters.PermissionsAdapter; import ru.urfu.taskmanager.task_manager.main.adapters.SavedFiltersAdapter; -import ru.urfu.taskmanager.task_manager.main.adapters.ViewPagerAdapter; import ru.urfu.taskmanager.task_manager.main.filter.FilterLayoutWrapper; import ru.urfu.taskmanager.task_manager.main.presenter.TaskManagerPresenter; import ru.urfu.taskmanager.task_manager.main.presenter.TaskManagerPresenterImpl; -import ru.urfu.taskmanager.task_manager.task_editor.view.TaskEditorActivity; -import ru.urfu.taskmanager.task_manager.task_editor.view.TaskEditorActivity_; -import ru.urfu.taskmanager.utils.db.DbTasksFilter; -import ru.urfu.taskmanager.utils.db.DbTasksHelper; import ru.urfu.taskmanager.utils.tools.DirectoryChooser; +import static ru.urfu.taskmanager.task_manager.editor.view.EditorPagerFragment.EDITOR_PAGER_POSITION; + @EActivity(R.layout.activity_task_list) public class TaskManagerActivity extends AppCompatActivity - implements TaskManager, MenuItemCompat.OnActionExpandListener, SearchView.OnQueryTextListener + implements TaskManager, + MenuItemCompat.OnActionExpandListener, + SearchView.OnQueryTextListener, + NavigationView.OnNavigationItemSelectedListener { - public static final String ACTION_CREATE = "ru.urfu.taskmanager.ACTION_CREATE"; - public static final String ACTION_EDIT = "ru.urfu.taskmanager.ACTION_EDIT"; - public static final int REQUEST_CREATE = 1; public static final int REQUEST_EDIT = 2; public static final int REQUEST_IMPORT = 3; @@ -69,30 +85,34 @@ private enum ToolbarMode { NORMAL, SEARCH, FILTER } + private BroadcastReceiver mBroadcastSyncManager; private FilterLayoutWrapper mFilterLayoutWrapper; private FiltersAdapter mAdapter; + @ViewById(R.id.drawer_layout) + DrawerLayout mDrawerLayout; + + @ViewById(R.id.nav_view) + NavigationView mNavigationView; + + @ViewById(R.id.fragment_place) + FrameLayout mFragmentLayout; + + @ViewById(R.id.nav_landscape_container) + FrameLayout mNavigationContainer; + @ViewById(R.id.animate_progress_bar) AnimateHorizontalProgressBar mProgressBar; @ViewById(R.id.circleProgressBar) ProgressBar mCircleProgressBar; - @ViewById(R.id.viewpager) - ViewPager mViewPager; - - @ViewById(R.id.tablayout) - TabLayout mTabLayout; - @ViewById(R.id.toolbar) Toolbar mToolbar; @ViewById(R.id.filter_layout) View mFilterLayout; - @ViewById(R.id.fab) - FloatingActionButton floatingActionButton; - ProgressDialog mProgressDialog; Spinner mSearchBySpinner; @@ -101,30 +121,70 @@ private enum ToolbarMode { MenuItem mSearchSpinnerItem; MenuItem mFilterCatalogMenuItem; - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); + @AfterViews + public void initialize() { + onConfigurationChanged(getResources().getConfiguration()); + + mPresenter = new TaskManagerPresenterImpl(this); + setupPermissionController(); - initialize(); + setupReceiver(); mAdapter = new SavedFiltersAdapter(this, this::onApplyFilter); mFilterLayoutWrapper = new FilterLayoutWrapper(mFilterLayout) .setFiltersAdapter(mAdapter) .onSaveButtonClick(this::onSaveFilter) .onApplyButtonClick(this::onApplyFilter); + + + setSupportActionBar(mToolbar); + mProgressDialog = new ProgressDialog(this); + mNavigationView.setNavigationItemSelectedListener(this); + + getSupportFragmentManager() + .beginTransaction() + .add(R.id.fragment_place, TaskPagerFragment.newInstance(new Bundle())) + .commit(); + + showAlert("USER_ID: " + User.getActiveUser().getUserId()); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); + mNavigationContainer.removeAllViews(); + } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); + + NavigationView navigationView = new NavigationView(this); + navigationView.inflateMenu(R.menu.nav_menu_bar); + navigationView.setNavigationItemSelectedListener(this); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + navigationView.setElevation(1f); + } - private void initialize() { - mPresenter = new TaskManagerPresenterImpl(this); + mNavigationContainer.addView(navigationView); + } + } - setSupportActionBar(mToolbar); - mViewPager.setOffscreenPageLimit(2); - setupViewPager(mViewPager); - mTabLayout.setupWithViewPager(mViewPager); + private void setupReceiver() { + IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + filter.addAction(BroadcastSyncManager.SYNC_ASK_ACTION); + filter.addAction(BroadcastSyncManager.SYNC_SUCCESS_ACTION); + filter.addAction(BroadcastSyncManager.SYNC_FAILED_ACTION); + filter.addAction(BroadcastSyncManager.SYNC_START_ACTION); + filter.addAction(BroadcastSyncManager.SYNC_SCHEDULE_ACTION); + + mBroadcastSyncManager = new BroadcastSyncManager(this) { + @Override + public void onStopSync() { + mPresenter.applyFilter(DbTasksFilter.DEFAULT_BUILDER); + } + }; - mProgressDialog = new ProgressDialog(this); - floatingActionButton.setOnClickListener(this); + registerReceiver(mBroadcastSyncManager, filter); } private void setupPermissionController() { @@ -147,15 +207,6 @@ public void onPermissionsChecked(MultiplePermissionsReport report) { .check(); } - private void setupViewPager(ViewPager viewPager) { - ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager()); - adapter.add(mPresenter.bindView(new TaskListActive()), getString(R.string.active_tasks_title)); - adapter.add(mPresenter.bindView(new TaskListCompleted()), getString(R.string.completed_tasks_title)); - - viewPager.setAdapter(adapter); - viewPager.setCurrentItem(0); - } - private void startToolbarMode(ToolbarMode startedToolbarMode) { switch (startedToolbarMode) { case FILTER: @@ -164,8 +215,7 @@ private void startToolbarMode(ToolbarMode startedToolbarMode) { mSearchSpinnerItem.setVisible(false); mFilterCatalogMenuItem.setVisible(true); - mViewPager.setVisibility(View.INVISIBLE); - mTabLayout.setVisibility(View.INVISIBLE); + mFragmentLayout.setVisibility(View.INVISIBLE); mFilterLayout.setVisibility(View.VISIBLE); mToolbar.setTitle(getString(R.string.toolbar_filter_title)); @@ -186,8 +236,7 @@ private void startToolbarMode(ToolbarMode startedToolbarMode) { mSearchSpinnerItem.setVisible(false); mFilterCatalogMenuItem.setVisible(false); - mViewPager.setVisibility(View.VISIBLE); - mTabLayout.setVisibility(View.VISIBLE); + mFragmentLayout.setVisibility(View.VISIBLE); mFilterLayout.setVisibility(View.GONE); mFilterMenuItem.setIcon(R.drawable.ic_sort); @@ -237,7 +286,6 @@ private void onApplyFilter(DbTasksFilter.Builder builder) { swapFilterLayout(); } - @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_task_list, menu); @@ -267,12 +315,27 @@ public boolean onCreateOptionsMenu(Menu menu) { return true; } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_IMPORT && resultCode == RESULT_OK) { + mPresenter.importData(data.getData()); + } + } + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_filter: swapFilterLayout(); break; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { case R.id.action_export: startDirectoryChooser(); break; @@ -285,9 +348,17 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.action_generation: generateBigData(); break; + case R.id.action_sync: + syncData(); + break; } - return super.onOptionsItemSelected(item); + return false; + } + + @Override + public void syncData() { + sendBroadcast(new Intent(BroadcastSyncManager.SYNC_START_ACTION)); } private void generateBigData() { @@ -331,28 +402,48 @@ public boolean onMenuItemActionCollapse(MenuItem item) { return true; } - @Override - public void startEditor(int id) { - Intent intent = new Intent(this, TaskEditorActivity_.class); - intent.setAction(ACTION_EDIT); - intent.putExtra(DbTasksHelper.ID, id); - startActivityForResult(intent, REQUEST_EDIT); + public TaskManagerPresenter getPresenter() { + return mPresenter; } @Override - public void onClick(View v) { - Intent intent = new Intent(this, TaskEditorActivity_.class); - intent.setAction(ACTION_CREATE); - startActivityForResult(intent, REQUEST_CREATE); + public FilterLayoutWrapper getFilterLayoutWrapper() { + return mFilterLayoutWrapper; } @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - mPresenter.onResult(requestCode, resultCode, data); - } + public void startEditor(@Nullable Integer position, CursorProvider adapter, TasksListAdapter.ViewHolder holder) { + Bundle bundle = new Bundle(); + bundle.putSerializable(EDITOR_PAGER_POSITION, position); + + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + Fragment editorFragment; + + if (position == null) { + editorFragment = TaskEditorFragment.newInstance(bundle); + } else { + editorFragment = EditorPagerFragment.newInstance(bundle, adapter); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && holder != null) { + editorFragment.setSharedElementEnterTransition(new CustomTransition()); + editorFragment.setSharedElementReturnTransition(new CustomTransition()); + editorFragment.setEnterTransition(new Fade(Fade.IN)); + editorFragment.setExitTransition(new Fade(Fade.OUT)); + getSupportFragmentManager().getFragments().get(0) + .setEnterTransition(new Fade(Fade.IN)); + getSupportFragmentManager().getFragments().get(0) + .setExitTransition(new Fade(Fade.OUT)); + + transaction.addSharedElement(holder.ttl, "timeBlock_" + position); + } + } + + transaction.replace(R.id.fragment_place, editorFragment) + .addToBackStack(null) + .commit(); + } @UiThread public void startProgressIndicator(int max) { @@ -372,8 +463,6 @@ public void stopProgressIndicator() { @UiThread public void showProgress(String title, String message) { - if (mProgressDialog.isShowing()) return; - mProgressDialog.setTitle(title); mProgressDialog.setMessage(message); mProgressDialog.setCancelable(false); @@ -383,14 +472,14 @@ public void showProgress(String title, String message) { @UiThread public void showProgress() { - mViewPager.setVisibility(View.GONE); + mFragmentLayout.setVisibility(View.INVISIBLE); mCircleProgressBar.setVisibility(View.VISIBLE); } @UiThread public void hideProgress() { mCircleProgressBar.setVisibility(View.GONE); - mViewPager.setVisibility(View.VISIBLE); + mFragmentLayout.setVisibility(View.VISIBLE); if (mProgressDialog.isShowing()) mProgressDialog.dismiss(); } @@ -399,10 +488,10 @@ public void showAlert(String message) { Snackbar.make(getWindow().getDecorView(), message, SNACKBAR_SHOW_TIME).show(); } - @Override protected void onDestroy() { mPresenter.onDestroy(); + unregisterReceiver(mBroadcastSyncManager); super.onDestroy(); } } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/models/OnDataUpdateListener.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/models/OnDataUpdateListener.java deleted file mode 100644 index ccf2c4f..0000000 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/models/OnDataUpdateListener.java +++ /dev/null @@ -1,6 +0,0 @@ -package ru.urfu.taskmanager.task_manager.models; - -public interface OnDataUpdateListener -{ - void onUpdate(T... data); -} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/models/TaskEntry.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/models/TaskEntry.java index 5e186be..c4a38d5 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/models/TaskEntry.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/models/TaskEntry.java @@ -3,40 +3,74 @@ import android.graphics.Color; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.ColorInt; + +import com.google.gson.annotations.SerializedName; import java.text.ParseException; +import ru.urfu.taskmanager.auth.models.User; import ru.urfu.taskmanager.utils.tools.ISO8601; +import ru.urfu.taskmanager.utils.tools.JSONFactory; public class TaskEntry implements Parcelable { - private int mId; - private int mComplete; + private transient int mAuthorId = User.getActiveUser().getUserId(); + + private transient int mId; + + private transient Integer mOrder = null; + + @SerializedName("id") + private Integer mEntryId; + + @SerializedName("extra") + private String deviceId; + + @SerializedName("title") + private String mTitle; + + @SerializedName("description") + private String mDescription; + + @SerializedName("created") + private String mCreated; + + @SerializedName("edited") + private String mEdited; + + @SerializedName("viewed") + private String mTimeToLive; - private String title; - private String description; - private String ttl; - private String created; - private String edited; - private String color; - private String imageUrl; + @SerializedName("imageUrl") + private String mImageUrl; + + @SerializedName("color") + private String mColor; public TaskEntry() { } public TaskEntry(int id) { this.mId = id; + this.mEntryId = null; + this.deviceId = User.getActiveUser().getDeviceIdentifier(); } - private TaskEntry(Parcel in) { - title = in.readString(); - description = in.readString(); - ttl = in.readString(); - color = in.readString(); - mComplete = in.readInt(); + protected TaskEntry(Parcel in) { + mId = in.readInt(); + deviceId = in.readString(); + mTitle = in.readString(); + mDescription = in.readString(); + mCreated = in.readString(); + mEdited = in.readString(); + mTimeToLive = in.readString(); + mImageUrl = in.readString(); + mColor = in.readString(); } - public static final Creator CREATOR = new Creator() { + public static final Creator CREATOR = new Creator() + { @Override public TaskEntry createFromParcel(Parcel in) { return new TaskEntry(in); @@ -48,6 +82,19 @@ public TaskEntry[] newArray(int size) { } }; + public TaskEntry setDeviceIdentifier(String hash) { + this.deviceId = hash; + return this; + } + + public String getDeviceIdentifier() { + return deviceId; + } + + public int getAuthorId() { + return mAuthorId; + } + public TaskEntry setId(int id) { this.mId = id; return this; @@ -57,40 +104,49 @@ public int getId() { return mId; } + public TaskEntry setEntryId(int id) { + this.mEntryId = id; + return this; + } + + public Integer getEntryId() { + return mEntryId; + } + public String getTitle() { - return title; + return mTitle; } public TaskEntry setTitle(String title) { - this.title = title; + this.mTitle = title; return this; } public String getDescription() { - return description; + return mDescription; } public TaskEntry setDescription(String description) { - this.description = description; + this.mDescription = description; return this; } public TaskEntry setImageUrl(String url) { - this.imageUrl = url; + this.mImageUrl = url; return this; } public String getImageUrl() { - return imageUrl; + return mImageUrl; } public String getTtl() { - return ttl; + return mTimeToLive; } public long getTtlTimestamp() { try { - return ISO8601.toTimestamp(ttl); + return ISO8601.toTimestamp(mTimeToLive); } catch (ParseException e) { e.printStackTrace(); return Long.MIN_VALUE; @@ -98,22 +154,22 @@ public long getTtlTimestamp() { } public TaskEntry setTtl(long ttl) { - this.ttl = ISO8601.fromTimestamp(ttl); + this.mTimeToLive = ISO8601.fromTimestamp(ttl); return this; } public TaskEntry setCreated(long created) { - this.created = ISO8601.fromTimestamp(created); + this.mCreated = ISO8601.fromTimestamp(created); return this; } public String getCreated() { - return created; + return mCreated; } public long getCreatedTimestamp() { try { - return ISO8601.toTimestamp(created); + return ISO8601.toTimestamp(mCreated); } catch (Exception e) { e.printStackTrace(); return Long.MIN_VALUE; @@ -121,17 +177,17 @@ public long getCreatedTimestamp() { } public TaskEntry setEdited(long edited) { - this.edited = ISO8601.fromTimestamp(edited); + this.mEdited = ISO8601.fromTimestamp(edited); return this; } public String getEdited() { - return edited; + return mEdited; } public long getEditedTimestamp() { try { - return ISO8601.toTimestamp(edited); + return ISO8601.toTimestamp(mEdited); } catch (ParseException e) { e.printStackTrace(); return Long.MIN_VALUE; @@ -139,38 +195,33 @@ public long getEditedTimestamp() { } public String getColor() { - return color; + return mColor; } public int getColorInt() { - return Color.parseColor(color); + return Color.parseColor(mColor); } - public TaskEntry setColor(int color) { - this.color = String.format("#%06X", (0xFFFFFF & color)); + public TaskEntry setColor(@ColorInt int color) { + this.mColor = String.format("#%06X", (0xFFFFFF & color)); return this; } public boolean isCompleted() { - return (mComplete == 1); - } - - public String getCompleted() { - return String.valueOf(mComplete); - } - - public TaskEntry setCompleted(boolean bool) { - mComplete = (bool) ? 1 : 0; - return this; + return mTimeToLive.equals(mEdited); } @Override public int hashCode() { int hash = 5; - hash = 89 * hash + (title != null ? title.hashCode() : 0); - hash = 89 * hash + (description != null ? description.hashCode() : 0); - hash = 89 * hash + color.hashCode(); + hash = 89 * hash + (mTitle != null ? mTitle.hashCode() : 0); + hash = 89 * hash + (mDescription != null ? mDescription.hashCode() : 0); + hash = 89 * hash + (mCreated != null ? (int) getCreatedTimestamp() : 0); + hash = 89 * hash + (mEdited != null ? (int) getEditedTimestamp() : 0); + hash = 89 * hash + (mTimeToLive != null ? (int) getTtlTimestamp() : 0); + hash = 89 * hash + (mImageUrl != null ? mImageUrl.hashCode() : 0); + hash = 89 * hash + (mColor != null ? mColor.hashCode() : 0); return hash; } @@ -179,30 +230,41 @@ public int hashCode() { public boolean equals(Object obj) { try { TaskEntry other = (TaskEntry) obj; - return this.mId == other.mId; + return this.mEntryId.equals(other.mEntryId); } catch (ClassCastException e) { return false; } } + @Override + public String toString() { + return JSONFactory.toJson(this, TaskEntry.class); + } + @Override public int describeContents() { - return CONTENTS_FILE_DESCRIPTOR; + return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mId); - dest.writeString(title); - dest.writeString(description); - dest.writeString(ttl); - dest.writeString(color); - dest.writeInt(mComplete); + dest.writeString(deviceId); + dest.writeString(mTitle); + dest.writeString(mDescription); + dest.writeString(mCreated); + dest.writeString(mEdited); + dest.writeString(mTimeToLive); + dest.writeString(mImageUrl); + dest.writeString(mColor); } - @Override - public String toString() { - return "[" + "title: " + title + "; " + "description: " + description + "; " + - "ttl: " + ttl + "; " + "color: " + color + "]"; + public Integer getOrder() { + return mOrder; + } + + public TaskEntry setOrder(int mOrder) { + this.mOrder = mOrder; + return this; } } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/models/TaskEntryCouples.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/models/TaskEntryCouples.java new file mode 100644 index 0000000..1634e6a --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/models/TaskEntryCouples.java @@ -0,0 +1,118 @@ +package ru.urfu.taskmanager.task_manager.models; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Iterator; + +public class TaskEntryCouples + implements Parcelable, Iterable +{ + private ArrayList data; + + public TaskEntryCouples() { + this.data = new ArrayList<>(); + } + + protected TaskEntryCouples(Parcel in) { + data = in.createTypedArrayList(Couple.CREATOR); + } + + public static final Creator CREATOR = new Creator() + { + @Override + public TaskEntryCouples createFromParcel(Parcel in) { + return new TaskEntryCouples(in); + } + + @Override + public TaskEntryCouples[] newArray(int size) { + return new TaskEntryCouples[size]; + } + }; + + public void put(TaskEntry key, TaskEntry value) { + data.add(new Couple(key, value)); + } + + public Couple remove(int index) { + return data.remove(index); + } + + public boolean remove(Couple couple) { + return data.remove(couple); + } + + public boolean isEmpty() { + return data.isEmpty(); + } + + public int size() { + return data.size(); + } + + @Override + public Iterator iterator() { + return data.iterator(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeTypedList(data); + } + + + public static class Couple implements Parcelable + { + private TaskEntry key; + private TaskEntry value; + + private Couple(TaskEntry key, TaskEntry value) { + this.key = key; + this.value = value; + } + + protected Couple(Parcel in) { + key = in.readParcelable(TaskEntry.class.getClassLoader()); + value = in.readParcelable(TaskEntry.class.getClassLoader()); + } + + public static final Creator CREATOR = new Creator() + { + @Override + public Couple createFromParcel(Parcel in) { + return new Couple(in); + } + + @Override + public Couple[] newArray(int size) { + return new Couple[size]; + } + }; + + public TaskEntry getKey() { + return key; + } + + public TaskEntry getValue() { + return value; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(key, flags); + dest.writeParcelable(value, flags); + } + } +} \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/presenter/TaskEditorPresenterImpl.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/presenter/TaskEditorPresenterImpl.java deleted file mode 100644 index f6f78b3..0000000 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/presenter/TaskEditorPresenterImpl.java +++ /dev/null @@ -1,111 +0,0 @@ -package ru.urfu.taskmanager.task_manager.task_editor.presenter; - -import ru.urfu.taskmanager.R; -import ru.urfu.taskmanager.color_picker.recent.RecentColorsStorage; -import ru.urfu.taskmanager.task_manager.main.view.TaskManagerActivity; -import ru.urfu.taskmanager.task_manager.models.TaskEntry; -import ru.urfu.taskmanager.task_manager.task_editor.view.TaskEditor; -import ru.urfu.taskmanager.utils.db.async.DbAsyncExecutor; -import ru.urfu.taskmanager.utils.db.DbTasks; -import ru.urfu.taskmanager.utils.db.DbTasksHelper; -import ru.urfu.taskmanager.utils.db.async.ExecuteControllerAdapter; -import ru.urfu.taskmanager.utils.interfaces.Callback; - -import static android.app.Activity.RESULT_OK; - -public class TaskEditorPresenterImpl implements TaskEditorPresenter -{ - private final int INVALID_ID = -1; - - private int mItemId; - - private TaskEditor mEditor; - private TaskValidator mValidator; - private DbAsyncExecutor dbAsyncExecutor; - private RecentColorsStorage mRecentColorsStorage; - - public TaskEditorPresenterImpl(TaskEditor editor) { - this.mEditor = editor; - this.dbAsyncExecutor = DbTasks.getInstance().getAsyncExecutor(); - this.mRecentColorsStorage = RecentColorsStorage.getRepository(); - this.mValidator = new TaskValidator(); - init(); - } - - private void init() { - if (mEditor.getIntent().getAction().equals(TaskManagerActivity.ACTION_EDIT)) { - mEditor.setToolbarTitle(mEditor.getResources().getString(R.string.editor_edit_title)); - mItemId = mEditor.getIntent().getIntExtra(DbTasksHelper.ID, INVALID_ID); - if (mItemId != INVALID_ID) { - dbAsyncExecutor.getEntryById(mItemId, - new ExecuteControllerAdapter() { - @Override - public void onFinish(TaskEntry result) { - if (!mEditor.isRestored()) - mEditor.initializeEditor(result); - mEditor.onImageLoad(result.getImageUrl()); - } - }); - } - } - } - - @Override - public void saveState(TaskEntry state) { - mValidator.validate(state, aVoid -> { - long timestamp = System.currentTimeMillis(); - - switch (mEditor.getIntent().getAction()) { - case TaskManagerActivity.ACTION_CREATE: - dbAsyncExecutor.insertEntry( - state.setId(mItemId) - .setCreated(timestamp) - .setEdited(timestamp) - ); - break; - case TaskManagerActivity.ACTION_EDIT: - dbAsyncExecutor.updateEntry( - state.setId(mItemId) - .setEdited(timestamp) - ); - break; - } - - mRecentColorsStorage.putItem(state.getColorInt()); - mEditor.exit(RESULT_OK); - }); - } - - private class TaskValidator { - private static final int TITLE_MAX_LENGTH = 20; - private static final int DESCRIPTION_MAX_LENGTH = 50; - - private boolean isValid = true; - - private void validate(TaskEntry entry, Callback callback) { - isValid = true; - - if (entry.getTitle().isEmpty()) { - isValid = false; - mEditor.showTitleError(mEditor.getResources().getString(R.string.search_hint)); - } - - if (entry.getTitle().length() > TITLE_MAX_LENGTH) { - isValid = false; - mEditor.showTitleError(mEditor.getResources().getString(R.string.incorrect_length) + " " + TITLE_MAX_LENGTH); - } - - if (entry.getDescription().isEmpty()) { - isValid = false; - mEditor.showDescriptionError(mEditor.getResources().getString(R.string.entry_description)); - } - - if (entry.getDescription().length() > DESCRIPTION_MAX_LENGTH) { - isValid = false; - mEditor.showTitleError(mEditor.getResources().getString(R.string.incorrect_length) + " " + DESCRIPTION_MAX_LENGTH); - } - - if (isValid) callback.call(null); - } - } -} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/view/TaskEditorActivity.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/view/TaskEditorActivity.java deleted file mode 100644 index 73ce86d..0000000 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/task_manager/task_editor/view/TaskEditorActivity.java +++ /dev/null @@ -1,245 +0,0 @@ -package ru.urfu.taskmanager.task_manager.task_editor.view; - -import android.graphics.Color; -import android.os.Bundle; -import android.os.Vibrator; -import android.support.design.widget.TextInputLayout; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.CardView; -import android.support.v7.widget.Toolbar; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.Toast; - -import com.github.florent37.singledateandtimepicker.SingleDateAndTimePicker; - -import org.androidannotations.annotations.EActivity; -import org.androidannotations.annotations.InstanceState; -import org.androidannotations.annotations.UiThread; -import org.androidannotations.annotations.ViewById; - -import java.io.IOException; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; - -import ru.urfu.taskmanager.R; -import ru.urfu.taskmanager.color_picker.PickerView; -import ru.urfu.taskmanager.color_picker.recent.RecentColors; -import ru.urfu.taskmanager.task_manager.models.TaskEntry; -import ru.urfu.taskmanager.task_manager.task_editor.presenter.TaskEditorPresenter; -import ru.urfu.taskmanager.task_manager.task_editor.presenter.TaskEditorPresenterImpl; -import ru.urfu.taskmanager.task_manager.task_editor.tools.ImageLoader; - -@EActivity(R.layout.activity_task_editor) -public class TaskEditorActivity extends AppCompatActivity implements TaskEditor -{ - private static final String CACHE_KEY = "color_cache"; - private static final String COLOR_KEY = "current_color"; - private static final String DATE_KEY = "selected_date"; - private static final int CELL_COUNT = 16; - - TaskEditorPresenter mPresenter; - - @ViewById(R.id.datetime_picker) - SingleDateAndTimePicker mDateTimePicker; - - @ViewById(R.id.title_input_layout) - TextInputLayout mTitleInputLayout; - - @ViewById(R.id.description_input_layout) - TextInputLayout mDescInputLayout; - - @ViewById(R.id.image_view) - ImageView mImageView; - - @ViewById(R.id.pickerView) - PickerView mPickerView; - - @ViewById(R.id.cardColor) - CardView mCardColorView; - - @ViewById(R.id.title_edit_field) - EditText mTitleEditField; - - @ViewById(R.id.descr_edit_field) - EditText mDescEditField; - - @ViewById(R.id.image_url_edit_field) - EditText mImageUrlEditField; - - @ViewById(R.id.save_button) - Button mButtonSave; - - boolean mRestored = false; - - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - if (savedInstanceState != null) mRestored = true; - - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - - if (getSupportActionBar() != null) { - getSupportActionBar().setTitle(getString(R.string.editor_create_title)); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setDisplayShowHomeEnabled(true); - } - - setResult(RESULT_CANCELED); - - mDateTimePicker.setMustBeOnFuture(true); - mButtonSave.setOnClickListener(this); - mPickerView.setCellCount(CELL_COUNT); - mPickerView.subscribe(this); - - mImageUrlEditField.addTextChangedListener(new TextWatcher() - { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - //Stub! - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - //Stub! - } - - @Override - public void afterTextChanged(Editable s) { - onImageLoad(s.toString()); - } - }); - - mCardColorView.setCardBackgroundColor(mPickerView.getCurrentColor()); - mCardColorView.setOnClickListener(v -> RecentColors.showRecent(this, color -> { - mPickerView.setCurrentColor(color); - mCardColorView.setCardBackgroundColor(color); - })); - - mPresenter = new TaskEditorPresenterImpl(this); - } - - public boolean isRestored() { - return mRestored; - } - - @UiThread - public void initializeEditor(TaskEntry entry) { - Calendar calendar = new GregorianCalendar(); - calendar.setTimeInMillis(entry.getTtlTimestamp()); - - mDateTimePicker.selectDate(calendar); - mDateTimePicker.setSelectorColor(Color.BLACK); - mTitleEditField.setText(entry.getTitle()); - mDescEditField.setText(entry.getDescription()); - mImageUrlEditField.setText(entry.getImageUrl()); - mPickerView.setCurrentColor(entry.getColorInt()); - mCardColorView.setCardBackgroundColor(mPickerView.getCurrentColor()); - } - - @Override - @UiThread - public void onImageLoad(String url) { - ImageLoader.into(mImageView) - .from(url); - } - - @Override - public void showTitleError(String string) { - mTitleInputLayout.setError(string); - } - - - @Override - public void showDescriptionError(String string) { - mDescInputLayout.setError(string); - } - - @Override - public void onClick(View v) { - mTitleInputLayout.setErrorEnabled(false); - mDescInputLayout.setErrorEnabled(false); - - mPresenter.saveState( - new TaskEntry() - .setTitle(mTitleEditField.getText().toString()) - .setDescription(mDescEditField.getText().toString()) - .setTtl(mDateTimePicker.getDate().getTime()) - .setColor(mPickerView.getCurrentColor()) - .setImageUrl(mImageUrlEditField.getText().toString()) - ); - } - - @Override - public void onColorChanged(int color) { - mCardColorView.setCardBackgroundColor(color); - } - - @Override - public void editModeEnable() { - vibrate(); - } - - @Override - public void editModeDisable() { - vibrate(); - } - - @Override - public void theBoundaryIsReached() { - vibrate(); - } - - private void vibrate() { - Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); - vibrator.vibrate(10); - } - - @Override - public boolean onSupportNavigateUp() { - onBackPressed(); - return true; - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - mPickerView.getColorCache(); - outState.putSerializable(CACHE_KEY, mPickerView.getColorCache()); - outState.putInt(COLOR_KEY, mPickerView.getCurrentColor()); - outState.putSerializable(DATE_KEY, mDateTimePicker.getDate()); - super.onSaveInstanceState(outState); - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - Calendar calendar = Calendar.getInstance(); - calendar.setTime((Date) savedInstanceState.getSerializable(DATE_KEY)); - float[][] cache = (float[][]) savedInstanceState.getSerializable(CACHE_KEY); - int currentColor = savedInstanceState.getInt(COLOR_KEY); - mPickerView.setColorCache(cache); - mPickerView.setCellCount(CELL_COUNT); - mPickerView.setCurrentColor(currentColor); - mCardColorView.setCardBackgroundColor(mPickerView.getCurrentColor()); - mDateTimePicker.selectDate(calendar); - } - - @Override - public void setToolbarTitle(String title) { - if (getSupportActionBar() != null) { - getSupportActionBar().setTitle(title); - } - } - - @Override - public void exit(int result) { - setResult(result); - finish(); - } -} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/interfaces/Thenable.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/interfaces/Thenable.java new file mode 100644 index 0000000..e1713c4 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/interfaces/Thenable.java @@ -0,0 +1,7 @@ +package ru.urfu.taskmanager.utils.interfaces; + +public interface Thenable +{ + void onSuccess(T... results); + void onFailed(Throwable t); +} diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/JSONFactory.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/JSONFactory.java index f0c13f0..fa02641 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/JSONFactory.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/JSONFactory.java @@ -4,6 +4,7 @@ import com.google.gson.GsonBuilder; import java.io.IOException; +import java.lang.reflect.Type; public class JSONFactory { @@ -17,4 +18,8 @@ public static String toJson(T object, Class _class) { public static T fromJson(String json, Class _class) throws IOException { return gson.fromJson(json, _class); } + + public static T fromJson(String json, Type type) throws IOException { + return gson.fromJson(json, type); + } } diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/NetworkUtil.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/NetworkUtil.java new file mode 100644 index 0000000..b271284 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/NetworkUtil.java @@ -0,0 +1,20 @@ +package ru.urfu.taskmanager.utils.tools; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +public final class NetworkUtil +{ + public static boolean networkIsReachable(Context context) { + ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + + NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); + if (null != activeNetwork) { + if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) return true; + if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/TimeUtils.java b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/TimeUtils.java index b39bfb8..71982ec 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/TimeUtils.java +++ b/Task3. TaskManager/TaskManager/app/src/main/java/ru/urfu/taskmanager/utils/tools/TimeUtils.java @@ -15,7 +15,7 @@ public final class TimeUtils private static final SimpleDateFormat sFormatter = new SimpleDateFormat("dd.MM.yyyy", sLocale); public static HoursAndMinutes getHoursAndMinutesFromUnix(long timestamp) { - Calendar calendar = new GregorianCalendar(); + Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(timestamp); HoursAndMinutes time = new HoursAndMinutes(); diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/drawable/ripple_task_item.xml b/Task3. TaskManager/TaskManager/app/src/main/res/drawable/ripple_task_item.xml new file mode 100644 index 0000000..2796800 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/res/drawable/ripple_task_item.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/layout-land/activity_task_editor.xml b/Task3. TaskManager/TaskManager/app/src/main/res/layout-land/activity_task_editor.xml deleted file mode 100644 index 2ae2f24..0000000 --- a/Task3. TaskManager/TaskManager/app/src/main/res/layout-land/activity_task_editor.xml +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/layout/active_tasks_fragment.xml b/Task3. TaskManager/TaskManager/app/src/main/res/layout/active_tasks_fragment.xml index 41afff9..597caff 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/res/layout/active_tasks_fragment.xml +++ b/Task3. TaskManager/TaskManager/app/src/main/res/layout/active_tasks_fragment.xml @@ -6,7 +6,7 @@ android:layout_height="match_parent" tools:context=".task_manager.main.view.TaskManagerActivity"> - + + + + + + + + + + + \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_editor.xml b/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_editor.xml index c4b817a..3ebb059 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_editor.xml +++ b/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_editor.xml @@ -1,136 +1,139 @@ - - - - - - - - - - - + android:orientation="vertical" + android:clickable="true"> - - - - + + + android:layout_marginBottom="56dp" + android:orientation="vertical"> - + android:scrollbars="none"/> - - - - - - - - - + + + + + + + + + + + + + - + - + - - - - - + + + + + + + + + + + + + + + + + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:padding="18dp" + android:text="@string/complete" + android:textSize="18sp"/> - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_filter.xml b/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_filter.xml index 01372d2..b04e499 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_filter.xml +++ b/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_filter.xml @@ -1,238 +1,244 @@ - + android:layout_height="match_parent" + android:visibility="invisible"> - - - - + android:layout_height="250dp" + android:background="@color/colorPrimaryDark" + android:visibility="gone"/> + + + android:orientation="vertical"> - + android:orientation="horizontal" + android:padding="16dp"> - + - + - + - + android:orientation="horizontal" + android:padding="16dp"> - + - + - - - + - + android:background="@color/half_lite_gray" + android:checkedButton="@+id/by_single_date_radio" + android:gravity="right" + android:orientation="horizontal" + android:padding="16dp" + android:visibility="gone"> - + - + - + - + android:background="@color/half_lite_gray" + android:orientation="horizontal" + android:padding="16dp" + android:visibility="gone"> - + - + - + - + - - - - - + android:orientation="horizontal" + android:padding="16dp"> - + + + + + - + - + android:orientation="horizontal" + android:padding="16dp"> - + - + - + - + android:orientation="horizontal" + android:padding="16dp"> - + android:layout_weight="1" + android:text="@string/order_by"/> - + android:layout_weight="1" + android:checkedButton="@+id/order_front_radio"> - + - + - + - + - + android:orientation="horizontal" + android:padding="16dp"> + + + + + + - + - + - \ No newline at end of file + \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_list.xml b/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_list.xml index edf451b..40eff04 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_list.xml +++ b/Task3. TaskManager/TaskManager/app/src/main/res/layout/activity_task_list.xml @@ -1,16 +1,19 @@ - + + android:layout_height="match_parent"> - + + - + - - - - - - + - + - + - + + + + + + + + + - + diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/layout/main_fragment.xml b/Task3. TaskManager/TaskManager/app/src/main/res/layout/main_fragment.xml new file mode 100644 index 0000000..65ef606 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/res/layout/main_fragment.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/layout/sync_conflict_layout.xml b/Task3. TaskManager/TaskManager/app/src/main/res/layout/sync_conflict_layout.xml new file mode 100644 index 0000000..a6c5194 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/res/layout/sync_conflict_layout.xml @@ -0,0 +1,34 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/layout/task_list_item.xml b/Task3. TaskManager/TaskManager/app/src/main/res/layout/task_list_item.xml index c5b8fd6..9547a2e 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/res/layout/task_list_item.xml +++ b/Task3. TaskManager/TaskManager/app/src/main/res/layout/task_list_item.xml @@ -1,9 +1,11 @@ - + diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/menu/menu_task_list.xml b/Task3. TaskManager/TaskManager/app/src/main/res/menu/menu_task_list.xml index 28f04d0..7b0d527 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/res/menu/menu_task_list.xml +++ b/Task3. TaskManager/TaskManager/app/src/main/res/menu/menu_task_list.xml @@ -30,20 +30,4 @@ app:actionLayout="@layout/toolbar_search_spinner" app:showAsAction="always"/> - - - - - - - diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/menu/nav_menu_bar.xml b/Task3. TaskManager/TaskManager/app/src/main/res/menu/nav_menu_bar.xml new file mode 100644 index 0000000..dc9f577 --- /dev/null +++ b/Task3. TaskManager/TaskManager/app/src/main/res/menu/nav_menu_bar.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/values/colors.xml b/Task3. TaskManager/TaskManager/app/src/main/res/values/colors.xml index 7fef674..ef7c1e6 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/res/values/colors.xml +++ b/Task3. TaskManager/TaskManager/app/src/main/res/values/colors.xml @@ -7,6 +7,7 @@ #848484 #FFFFFF #e9e9e9 + #f4f4f4 #e2e2e2 #000000 diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/values/strings.xml b/Task3. TaskManager/TaskManager/app/src/main/res/values/strings.xml index 6d374d6..49fb442 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/res/values/strings.xml +++ b/Task3. TaskManager/TaskManager/app/src/main/res/values/strings.xml @@ -31,7 +31,7 @@ Название Примечание Готово - Сортировать по дате + Сортировать по Вывод по дате по дате по диапазону @@ -56,11 +56,18 @@ Сбор данных начался Собрано данных Не удалось загрузить изображение + Конфликт изменений + Нажмите на вариант, который хотите сохранить. + Не удалось синхронизировать данные + Успешно синхронизировано + Синхронизация… + Не удалось разрешить конфликт - Выполнения - Создания - Редактирования + Дате выполнения + Дате создания + Дате редактирования + Порядку diff --git a/Task3. TaskManager/TaskManager/app/src/main/res/values/styles.xml b/Task3. TaskManager/TaskManager/app/src/main/res/values/styles.xml index 4f9f9c7..ffa5b34 100644 --- a/Task3. TaskManager/TaskManager/app/src/main/res/values/styles.xml +++ b/Task3. TaskManager/TaskManager/app/src/main/res/values/styles.xml @@ -1,4 +1,4 @@ - + + + + + +