From 9259aaab190d3b5ebbdf7917ac614909d52bc66f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB?= <119668441+Jiga228@users.noreply.github.com> Date: Wed, 14 May 2025 16:55:49 +0700 Subject: [PATCH] Update --- .idea/vcs.xml | 6 + app/build.gradle.kts | 2 +- app/src/main/AndroidManifest.xml | 4 +- .../tasktracker/Activities/AddNewTask.java | 46 +-- .../Activities/DatePickerFragment.java | 22 ++ .../tasktracker/Activities/EditTask.java | 128 +++++++++ .../tasktracker/Activities/LoginActivity.java | 47 +++- .../tasktracker/Activities/MainMenu.java | 265 ++++++++++-------- .../{ => ViewModels}/AddItemViewModel.java | 5 +- .../ViewModels/EditTaskViewModel.java | 106 +++++++ .../{ => ViewModels}/MainMenuViewModel.java | 4 +- .../com/example/tasktracker/Answers/Task.java | 4 +- .../example/tasktracker/Api/ApiService.java | 10 +- .../com/example/tasktracker/Api/TaskDao.java | 3 + .../example/tasktracker/PublicKeyNames.java | 6 + app/src/main/res/drawable/add.png | Bin 0 -> 17923 bytes app/src/main/res/drawable/exit.png | Bin 0 -> 9197 bytes .../main/res/layout/activity_add_new_task.xml | 53 +--- .../main/res/layout/activity_edit_task.xml | 37 +++ .../main/res/layout/activity_main_menu.xml | 12 +- app/src/main/res/values-en/strings.xml | 5 +- app/src/main/res/values-ru/strings.xml | 5 +- app/src/main/res/values/strings.xml | 9 +- 23 files changed, 567 insertions(+), 212 deletions(-) create mode 100644 .idea/vcs.xml create mode 100644 app/src/main/java/com/example/tasktracker/Activities/DatePickerFragment.java create mode 100644 app/src/main/java/com/example/tasktracker/Activities/EditTask.java rename app/src/main/java/com/example/tasktracker/Activities/{ => ViewModels}/AddItemViewModel.java (92%) create mode 100644 app/src/main/java/com/example/tasktracker/Activities/ViewModels/EditTaskViewModel.java rename app/src/main/java/com/example/tasktracker/Activities/{ => ViewModels}/MainMenuViewModel.java (93%) create mode 100644 app/src/main/java/com/example/tasktracker/PublicKeyNames.java create mode 100644 app/src/main/res/drawable/add.png create mode 100644 app/src/main/res/drawable/exit.png create mode 100644 app/src/main/res/layout/activity_edit_task.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6b831bb..805d141 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -4,7 +4,7 @@ plugins { android { namespace = "com.example.tasktracker" - compileSdk = 35 + compileSdk = 36 defaultConfig { applicationId = "com.example.tasktracker" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 819adcd..a15ba51 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,7 +17,9 @@ android:theme="@style/Theme.TaskTracker" android:usesCleartextTraffic="true" tools:targetApi="31"> - + diff --git a/app/src/main/java/com/example/tasktracker/Activities/AddNewTask.java b/app/src/main/java/com/example/tasktracker/Activities/AddNewTask.java index ef52dbb..8fddcda 100644 --- a/app/src/main/java/com/example/tasktracker/Activities/AddNewTask.java +++ b/app/src/main/java/com/example/tasktracker/Activities/AddNewTask.java @@ -1,28 +1,32 @@ package com.example.tasktracker.Activities; +import android.app.DatePickerDialog; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; +import android.widget.DatePicker; import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; +import com.example.tasktracker.Activities.ViewModels.AddItemViewModel; import com.example.tasktracker.Answers.Task; +import com.example.tasktracker.PublicKeyNames; import com.example.tasktracker.R; import com.example.tasktracker.databinding.ActivityAddNewTaskBinding; import com.google.android.material.snackbar.Snackbar; import java.util.Random; -public class AddNewTask extends AppCompatActivity { +public class AddNewTask extends AppCompatActivity implements DatePickerDialog.OnDateSetListener { private static final String TAG = "ADD_NEW_TASK"; - private static final String TOKEN_KEY = "TOKEN"; private ActivityAddNewTaskBinding binding; private static String token; private AddItemViewModel viewModel; + private String stringDate = ""; @Override protected void onCreate(Bundle savedInstanceState) { @@ -30,13 +34,20 @@ public class AddNewTask extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(binding.getRoot()); - token = getIntent().getStringExtra(TOKEN_KEY); + token = getIntent().getStringExtra(PublicKeyNames.TOKEN_KEY); if(token == null) { Log.w(TAG, "Token is null"); return; } + + binding.btnDatePick.setOnClickListener(v->{ + DatePickerFragment fragment; + fragment = new DatePickerFragment(); + fragment.show(getSupportFragmentManager(), "DATE PICK"); + }); + viewModel = new ViewModelProvider(this).get(AddItemViewModel.class); viewModel.getClose().observe(this, new Observer() { @Override @@ -60,19 +71,18 @@ public class AddNewTask extends AppCompatActivity { binding.AddTask.setOnClickListener(v->{ String name = binding.TaskName.getText().toString(); String description = binding.TaskDescription.getText().toString(); - String date = getDate(); if(name.isEmpty()) { Snackbar.make(binding.getRoot(), R.string.snackbar_EnterName, Snackbar.LENGTH_SHORT).show(); return; } - if(date.isEmpty()) { + if(stringDate.isEmpty()) { Snackbar.make(binding.getRoot(), R.string.snackbar_EnterDate, Snackbar.LENGTH_SHORT).show(); return; } - long ID = generateID(name, description, date); - Task task = new Task(ID, name, description, date); + long ID = generateID(name, description, stringDate); + Task task = new Task(ID, name, description, stringDate); viewModel.OfflineSaveData(task); }); } @@ -88,7 +98,7 @@ public class AddNewTask extends AppCompatActivity { binding.AddTask.setOnClickListener(v->{ String name = binding.TaskName.getText().toString(); String description = binding.TaskDescription.getText().toString(); - String date = getDate(); + String date = binding.btnDatePick.getText().toString(); if(name.isEmpty()) { Snackbar.make(binding.getRoot(), R.string.snackbar_EnterName, Snackbar.LENGTH_SHORT).show(); @@ -105,16 +115,6 @@ public class AddNewTask extends AppCompatActivity { }); } - private String getDate() { - String day = binding.day.getText().toString(); - String month = binding.month.getText().toString(); - String year = binding.year.getText().toString(); - String minute = binding.minute.getText().toString(); - String hour = binding.hour.getText().toString(); - - return day + '.' + month + '.' + year + ' ' + minute + ':' + hour; - } - private long generateID(String name, String Description, String date) { Random rand = new Random(); @@ -129,7 +129,15 @@ public class AddNewTask extends AppCompatActivity { public static Intent getIntent(Context context, String token) { Intent intent = new Intent(context, AddNewTask.class); - intent.putExtra(TOKEN_KEY, token); + intent.putExtra(PublicKeyNames.TOKEN_KEY, token); return intent; } + + @Override + public void onDateSet(DatePicker datePicker, int year, int month, int day) { + stringDate = Integer.toString(day) + '.' + + Integer.toString(month) + '.' + + Integer.toString(year); + binding.btnDatePick.setText(stringDate); + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/tasktracker/Activities/DatePickerFragment.java b/app/src/main/java/com/example/tasktracker/Activities/DatePickerFragment.java new file mode 100644 index 0000000..7ec6c0b --- /dev/null +++ b/app/src/main/java/com/example/tasktracker/Activities/DatePickerFragment.java @@ -0,0 +1,22 @@ +package com.example.tasktracker.Activities; + +import android.app.DatePickerDialog; +import android.app.Dialog; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import java.util.Calendar; + +public class DatePickerFragment extends DialogFragment { + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Calendar mCalendar = Calendar.getInstance(); + int year = mCalendar.get(Calendar.YEAR); + int month = mCalendar.get(Calendar.MONTH); + int dayOfMonth = mCalendar.get(Calendar.DAY_OF_MONTH); + return new DatePickerDialog(getActivity(), (DatePickerDialog.OnDateSetListener) + getActivity(), year, month, dayOfMonth); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/tasktracker/Activities/EditTask.java b/app/src/main/java/com/example/tasktracker/Activities/EditTask.java new file mode 100644 index 0000000..a25322b --- /dev/null +++ b/app/src/main/java/com/example/tasktracker/Activities/EditTask.java @@ -0,0 +1,128 @@ +package com.example.tasktracker.Activities; + +import android.app.DatePickerDialog; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.widget.DatePicker; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.lifecycle.Observer; + +import com.example.tasktracker.Activities.ViewModels.EditTaskViewModel; +import com.example.tasktracker.Answers.Task; +import com.example.tasktracker.PublicKeyNames; +import com.example.tasktracker.R; +import com.example.tasktracker.databinding.ActivityEditTaskBinding; +import com.google.android.material.snackbar.Snackbar; + +public class EditTask extends AppCompatActivity implements DatePickerDialog.OnDateSetListener { + private static final String TAG = "EDIT_TASK"; + private static final String TASK_ID_KEY = "TASK_ID"; + + private ActivityEditTaskBinding binding; + private EditTaskViewModel viewModel; + private String token; + private long taskID = -1; + private String taskDateString; + + @Override + protected void onCreate(Bundle savedInstanceState) { + viewModel = new EditTaskViewModel(getApplication()); + binding = ActivityEditTaskBinding.inflate(getLayoutInflater()); + super.onCreate(savedInstanceState); + setContentView(binding.getRoot()); + + Intent intent = getIntent(); + taskID = intent.getLongExtra(TASK_ID_KEY, -1); + if(taskID == -1) { + Log.w(TAG, "No task id"); + return; + } + + binding.btnDatePick.setOnClickListener(v->{ // <----- + DatePickerFragment fragment; + fragment = new DatePickerFragment(); + fragment.show(getSupportFragmentManager(), "DATE PICK"); + }); + + viewModel.isLoading().observe(this, new Observer() { + @Override + public void onChanged(Task task) { + binding.TaskName.setText(task.getTaskName()); + binding.TaskDescription.setText(task.getTaskDescription()); + taskDateString = task.getTaskDate(); + binding.btnDatePick.setText(taskDateString); + } + }); + viewModel.getClose().observe(this, new Observer() { + @Override + public void onChanged(Boolean aBoolean) { + if(aBoolean) + finish(); + } + }); + + token = intent.getStringExtra(PublicKeyNames.TOKEN_KEY); + if(token == null) + { + Log.w(TAG, "Token is null"); + return; + } + + // Offline + if(token.equals("null")) { + Offline(); + } + // Online + else { + Online(); + } + } + + private void Offline() { + viewModel.LoadTaskOffline(taskID, this); + binding.btnEditTask.setOnClickListener(v->{ + String name = binding.TaskName.getText().toString(); + String description = binding.TaskDescription.getText().toString(); + + Task task = new Task(taskID, name, description, taskDateString); + viewModel.OfflineSaveData(task); + }); + } + + private void Online() { + binding.btnEditTask.setOnClickListener(v->{ + String name = binding.TaskName.getText().toString(); + String description = binding.TaskDescription.getText().toString(); + + Task task = new Task(taskID, name, description, taskDateString); + viewModel.OnlineSaveData(task, token); + }); + viewModel.getLiveDataFail().observe(this, new Observer() { + @Override + public void onChanged(String s) { + Snackbar.make(binding.getRoot(), R.string.snackbar_InternetError, Snackbar.LENGTH_LONG).show(); + Log.w(TAG, s); + } + }); + + viewModel.LoadTaskOnline(token, taskID); + } + + public static Intent getIntent(Context context, String token, long taskID) { + Intent intent = new Intent(context, EditTask.class); + intent.putExtra(PublicKeyNames.TOKEN_KEY, token); + intent.putExtra(TASK_ID_KEY, taskID); + return intent; + } + + @Override + public void onDateSet(DatePicker datePicker, int year, int month, int day) { + taskDateString = Integer.toString(day) + '.' + + Integer.toString(month) + '.' + + Integer.toString(year); + binding.btnDatePick.setText(taskDateString); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/tasktracker/Activities/LoginActivity.java b/app/src/main/java/com/example/tasktracker/Activities/LoginActivity.java index 9f08c41..d17ed68 100644 --- a/app/src/main/java/com/example/tasktracker/Activities/LoginActivity.java +++ b/app/src/main/java/com/example/tasktracker/Activities/LoginActivity.java @@ -1,7 +1,9 @@ package com.example.tasktracker.Activities; import android.annotation.SuppressLint; +import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; @@ -10,10 +12,13 @@ import androidx.appcompat.app.AppCompatActivity; import com.example.tasktracker.Answers.LoginAnswer; import com.example.tasktracker.Api.ApiFactory; +import com.example.tasktracker.PublicKeyNames; import com.example.tasktracker.R; import com.example.tasktracker.databinding.ActivityLoginBinding; import com.google.android.material.snackbar.Snackbar; +import java.util.Objects; + import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.disposables.CompositeDisposable; @@ -24,7 +29,12 @@ import io.reactivex.rxjava3.schedulers.Schedulers; public class LoginActivity extends AppCompatActivity { private static final String TAG = "LOGIN_ACTIVITY"; private ActivityLoginBinding binding; - private CompositeDisposable compositeDisposable = new CompositeDisposable(); + private SharedPreferences sharedPreferences; + private final CompositeDisposable compositeDisposable = new CompositeDisposable(); + + public static Intent getIntent(Context context) { + return new Intent(context, LoginActivity.class); + } @SuppressLint("UnsafeIntentLaunch") @Override @@ -34,6 +44,33 @@ public class LoginActivity extends AppCompatActivity { EdgeToEdge.enable(this); setContentView(binding.getRoot()); + sharedPreferences = getSharedPreferences(PublicKeyNames.TOKEN_LIST, MODE_PRIVATE); + String token = sharedPreferences.getString(PublicKeyNames.TOKEN_KEY, ""); + if(!token.isEmpty()) + { + Disposable disposable = ApiFactory.getApiService() + .checkToken(token) + .observeOn(Schedulers.io()).subscribe(new Consumer() { + @Override + public void accept(LoginAnswer loginAnswer) throws Throwable { + if(loginAnswer.getStatus().equals("ok")) { + Intent intent = MainMenu.getIntent(LoginActivity.this, token); + startActivity(intent); + finish(); + } else { + sharedPreferences.edit().putString(PublicKeyNames.TOKEN_KEY, "").apply(); + } + } + }, new Consumer() { + @Override + public void accept(Throwable throwable) throws Throwable { + Snackbar.make(binding.getRoot(), R.string.snackbar_InternetError, Snackbar.LENGTH_LONG).show(); + Log.e(TAG, Objects.requireNonNull(throwable.getMessage())); + } + }); + compositeDisposable.add(disposable); + } + binding.buttonSingIn.setOnClickListener(v->{ SingIn(); }); binding.buttonSingUp.setOnClickListener(v->{ SingUp(); }); @@ -74,6 +111,7 @@ public class LoginActivity extends AppCompatActivity { } String token = loginAnswer.getToken(); + sharedPreferences.edit().putString(PublicKeyNames.TOKEN_KEY, token).apply(); OpenMainMenu(token); } }, new Consumer() { @@ -115,6 +153,7 @@ public class LoginActivity extends AppCompatActivity { } String token = loginAnswer.getToken(); + sharedPreferences.edit().putString(PublicKeyNames.TOKEN_KEY, token).apply(); OpenMainMenu(token); } }, new Consumer() { @@ -127,6 +166,12 @@ public class LoginActivity extends AppCompatActivity { compositeDisposable.add(disposable); } + @Override + protected void onDestroy() { + super.onDestroy(); + compositeDisposable.dispose(); + } + private void OpenMainMenu(String token) { @SuppressLint("UnsafeIntentLaunch") diff --git a/app/src/main/java/com/example/tasktracker/Activities/MainMenu.java b/app/src/main/java/com/example/tasktracker/Activities/MainMenu.java index 996cf39..f601f11 100644 --- a/app/src/main/java/com/example/tasktracker/Activities/MainMenu.java +++ b/app/src/main/java/com/example/tasktracker/Activities/MainMenu.java @@ -1,7 +1,9 @@ package com.example.tasktracker.Activities; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.text.Editable; @@ -15,15 +17,16 @@ import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.RecyclerView; +import com.example.tasktracker.Activities.ViewModels.MainMenuViewModel; import com.example.tasktracker.Answers.Task; import com.example.tasktracker.Api.ApiFactory; import com.example.tasktracker.Api.TaskRepository; +import com.example.tasktracker.PublicKeyNames; import com.example.tasktracker.R; import com.example.tasktracker.databinding.ActivityMainMenuBinding; import com.google.android.material.snackbar.Snackbar; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.Objects; @@ -33,14 +36,12 @@ import retrofit2.Response; public class MainMenu extends AppCompatActivity { private static final String TAG = "MainMenu"; - private static final String TOKEN_KEY = "TOKEN"; private ActivityMainMenuBinding binding; private String token; private TaskAdapter taskAdapter; private MainMenuViewModel viewModel; - - private List taskListCache; + private List taskListCache = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { @@ -48,19 +49,27 @@ public class MainMenu extends AppCompatActivity { binding = ActivityMainMenuBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - token = getIntent().getStringExtra(TOKEN_KEY); - if(token == null) - { + token = getIntent().getStringExtra(PublicKeyNames.TOKEN_KEY); + if (token == null) { Log.e(TAG, "Token is empty"); return; } taskAdapter = new TaskAdapter(); binding.scrollTask.setAdapter(taskAdapter); - binding.buttonAddNewTask.setOnClickListener(v->{ + binding.buttonAddNewTask.setOnClickListener(v -> { Intent intent = AddNewTask.getIntent(this, token); startActivity(intent); }); + taskAdapter.setOnItemClick(new TaskAdapter.OnItemClick() { + @Override + public void Click(int position) { + Task task = taskAdapter.getTaskList().get(position); + @SuppressLint("UnsafeIntentLaunch") + Intent intent = EditTask.getIntent(MainMenu.this, token, task.getID()); + startActivity(intent); + } + }); viewModel = new ViewModelProvider(this).get(MainMenuViewModel.class); binding.findLine.addTextChangedListener(new TextWatcher() { @@ -72,8 +81,8 @@ public class MainMenu extends AppCompatActivity { @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { String find = binding.findLine.getText().toString(); - if(find.isEmpty()) { - if(token.equals("null")) { + if (find.isEmpty()) { + if (token.equals("null")) { TaskRepository.newInstance(getApplication()).taskDao().getTaskList().observe(MainMenu.this, new Observer>() { @Override public void onChanged(List tasks) { @@ -81,8 +90,7 @@ public class MainMenu extends AppCompatActivity { taskAdapter.setTaskList(tasks); } }); - } - else { + } else { viewModel.OnlineUpdateList(token); } } @@ -112,121 +120,138 @@ public class MainMenu extends AppCompatActivity { } }); - // offline - if(token.equals("null")) { - Offline(); + binding.buttonSingOut.setOnClickListener(v -> { + getSharedPreferences(PublicKeyNames.TOKEN_LIST, MODE_PRIVATE). + edit(). + remove(PublicKeyNames.TOKEN_KEY). + apply(); + + @SuppressLint("UnsafeIntentLaunch") + Intent intent = LoginActivity.getIntent(MainMenu.this); + startActivity(intent); + finish(); + }); + + // offline + if (token.equals("null")) { + Offline(); + } + //online + else { + Online(); + } } - //online - else { - Online(); - } - } - public void Offline() { - viewModel.getOnLoad().observe(this, new Observer>() { - @Override - public void onChanged(List tasks) { - taskListCache = tasks; - taskAdapter.setTaskList(tasks); - } - }); - - ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, - ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { - @Override - public boolean onMove(@NonNull RecyclerView recyclerView, - @NonNull RecyclerView.ViewHolder viewHolder, - @NonNull RecyclerView.ViewHolder target) { - return false; - } - - @Override - public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { - int position = viewHolder.getAdapterPosition(); - - Task task = taskAdapter.getItem(position); - new Thread(new Runnable() { - @Override - public void run() { - TaskRepository.newInstance(getApplication()).taskDao().delete(task); - } - }).start(); - taskAdapter.removeItemByPosition(position); - } - }); - helper.attachToRecyclerView(binding.scrollTask); - } - - private void Online() { - - viewModel.getOnLoad().observe(this, new Observer>() { - @Override - public void onChanged(List tasks) { - taskListCache = tasks; - taskAdapter.setTaskList(tasks); - } - }); - viewModel.onFail().observe(this, new Observer() { - @Override - public void onChanged(String s) { - Snackbar.make(binding.getRoot(), R.string.snackbar_InternetError, Snackbar.LENGTH_LONG).show(); - Log.w(TAG, s); - } - }); - - ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, - ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { - @Override - public boolean onMove(@NonNull RecyclerView recyclerView, - @NonNull RecyclerView.ViewHolder viewHolder, - @NonNull RecyclerView.ViewHolder target) { - return false; - } - - @Override - public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { - int position = viewHolder.getAdapterPosition(); - - Task task = taskAdapter.getItem(position); - ApiFactory.getApiService().removeTask(token, task.getID()).enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - Task task = taskAdapter.getItem(position); - taskAdapter.removeItemByPosition(position); - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { - Snackbar.make(binding.getRoot(), R.string.snackbar_InternetError, Snackbar.LENGTH_LONG).show(); - Log.w(TAG, Objects.requireNonNull(throwable.getMessage())); - } - }); - } - }); - helper.attachToRecyclerView(binding.scrollTask); - } - - @Override - protected void onResume() { - super.onResume(); - if(token.equals("null")) { - TaskRepository.newInstance(getApplication()).taskDao().getTaskList().observe(this, new Observer>() { + public void Offline () { + viewModel.getOnLoad().observe(this, new Observer>() { @Override public void onChanged(List tasks) { taskListCache = tasks; taskAdapter.setTaskList(tasks); } }); - } - else { - viewModel.OnlineUpdateList(token); - } - } - public static Intent getIntent(Context context, String token) { - Intent intent = new Intent(context, MainMenu.class); - intent.putExtra(TOKEN_KEY, token); - return intent; - } + ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, + ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, + @NonNull RecyclerView.ViewHolder viewHolder, + @NonNull RecyclerView.ViewHolder target) { + return false; + } -} \ No newline at end of file + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { + int position = viewHolder.getAdapterPosition(); + + Task task = taskAdapter.getItem(position); + new Thread(new Runnable() { + @Override + public void run() { + TaskRepository.newInstance(getApplication()).taskDao().delete(task); + for (int i = 0; i < taskListCache.size(); ++i) { + if (taskListCache.get(i).getID() == task.getID()) { + taskListCache.remove(i); + break; + } + } + } + }).start(); + taskAdapter.removeItemByPosition(position); + } + }); + helper.attachToRecyclerView(binding.scrollTask); + } + + private void Online () { + + viewModel.getOnLoad().observe(this, new Observer>() { + @Override + public void onChanged(List tasks) { + taskListCache = tasks; + taskAdapter.setTaskList(tasks); + } + }); + viewModel.onFail().observe(this, new Observer() { + @Override + public void onChanged(String s) { + Snackbar.make(binding.getRoot(), R.string.snackbar_InternetError, Snackbar.LENGTH_LONG).show(); + Log.w(TAG, s); + } + }); + + ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, + ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, + @NonNull RecyclerView.ViewHolder viewHolder, + @NonNull RecyclerView.ViewHolder target) { + return false; + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { + int position = viewHolder.getAdapterPosition(); + + Task task = taskAdapter.getItem(position); + ApiFactory.getApiService().removeTask(token, task.getID()).enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + Task task = taskAdapter.getItem(position); + taskAdapter.removeItemByPosition(position); + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { + Snackbar.make(binding.getRoot(), R.string.snackbar_InternetError, Snackbar.LENGTH_LONG).show(); + Log.w(TAG, Objects.requireNonNull(throwable.getMessage())); + } + }); + } + }); + helper.attachToRecyclerView(binding.scrollTask); + } + + @Override + protected void onResume () { + super.onResume(); + if (token.equals("null")) { + TaskRepository.newInstance(getApplication()).taskDao().getTaskList().observe(this, new Observer>() { + @Override + public void onChanged(List tasks) { + taskListCache = tasks; + taskAdapter.setTaskList(tasks); + } + }); + } else { + viewModel.OnlineUpdateList(token); + } + } + + public static Intent getIntent (Context context, String token){ + Intent intent = new Intent(context, MainMenu.class); + intent.putExtra(PublicKeyNames.TOKEN_KEY, token); + return intent; + } + + } \ No newline at end of file diff --git a/app/src/main/java/com/example/tasktracker/Activities/AddItemViewModel.java b/app/src/main/java/com/example/tasktracker/Activities/ViewModels/AddItemViewModel.java similarity index 92% rename from app/src/main/java/com/example/tasktracker/Activities/AddItemViewModel.java rename to app/src/main/java/com/example/tasktracker/Activities/ViewModels/AddItemViewModel.java index d48a1f3..e478f90 100644 --- a/app/src/main/java/com/example/tasktracker/Activities/AddItemViewModel.java +++ b/app/src/main/java/com/example/tasktracker/Activities/ViewModels/AddItemViewModel.java @@ -1,4 +1,4 @@ -package com.example.tasktracker.Activities; +package com.example.tasktracker.Activities.ViewModels; import android.app.Application; import android.util.Log; @@ -7,7 +7,6 @@ import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.Observer; import com.example.tasktracker.Answers.Task; import com.example.tasktracker.Api.ApiFactory; @@ -38,7 +37,7 @@ public class AddItemViewModel extends AndroidViewModel { public void OnlineSaveData(Task task, String token) { - Call send = ApiFactory.getApiService().addTask(token, task); + Call send = ApiFactory.getApiService().editTask(token, task); send.enqueue(new Callback() { @Override public void onResponse(@NonNull Call call, @NonNull Response response) { diff --git a/app/src/main/java/com/example/tasktracker/Activities/ViewModels/EditTaskViewModel.java b/app/src/main/java/com/example/tasktracker/Activities/ViewModels/EditTaskViewModel.java new file mode 100644 index 0000000..662f53c --- /dev/null +++ b/app/src/main/java/com/example/tasktracker/Activities/ViewModels/EditTaskViewModel.java @@ -0,0 +1,106 @@ +package com.example.tasktracker.Activities.ViewModels; + +import android.app.Application; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Observer; + +import com.example.tasktracker.Activities.EditTask; +import com.example.tasktracker.Answers.Task; +import com.example.tasktracker.Api.ApiFactory; +import com.example.tasktracker.Api.TaskDao; +import com.example.tasktracker.Api.TaskRepository; + +import io.reactivex.rxjava3.disposables.CompositeDisposable; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.functions.Consumer; +import io.reactivex.rxjava3.schedulers.Schedulers; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class EditTaskViewModel extends AndroidViewModel { + private static final String TAG = "EDIT_ITEM_VIEW_MODEL"; + + private final CompositeDisposable compositeDisposable = new CompositeDisposable(); + private final MutableLiveData liveDataSave = new MutableLiveData<>(); + private final MutableLiveData liveDataFail = new MutableLiveData<>(); + private final MutableLiveData liveDataLoad = new MutableLiveData<>(); + + public EditTaskViewModel(@NonNull Application application) { + super(application); + } + + public void OfflineSaveData(Task task) { + new Thread(new Runnable() { + @Override + public void run() { + TaskRepository.newInstance(getApplication()).taskDao().addTask(task); + liveDataSave.postValue(true); + } + }).start(); + } + + public void OnlineSaveData(Task task, String token) { + + Call send = ApiFactory.getApiService().editTask(token, task); + send.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + Log.d(TAG, "Task update successfully"); + liveDataSave.postValue(true); + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { + Log.w(TAG, throwable.toString()); + liveDataFail.postValue(throwable.getMessage()); + } + }); + } + + public void LoadTaskOffline(long taskID, EditTask owner) { + TaskRepository.newInstance(getApplication()).taskDao().getTask(taskID).observe(owner, new Observer() { + @Override + public void onChanged(Task task) { + liveDataLoad.postValue(task); + } + }); + } + + public void LoadTaskOnline(String token, long taskID) { + Disposable disposable = ApiFactory.getApiService().getTask(token, taskID) + .subscribeOn(Schedulers.io()).subscribe(new Consumer() { + @Override + public void accept(Task task) throws Throwable { + liveDataLoad.postValue(task); + } + }, new Consumer() { + @Override + public void accept(Throwable throwable) throws Throwable { + liveDataFail.postValue(throwable.getMessage()); + } + }); + compositeDisposable.add(disposable); + } + + @Override + protected void onCleared() { + super.onCleared(); + compositeDisposable.dispose(); + } + + public LiveData isLoading() { + return liveDataLoad; + } + public LiveData getLiveDataFail() { + return liveDataFail; + } + public LiveData getClose() { + return liveDataSave; + } +} diff --git a/app/src/main/java/com/example/tasktracker/Activities/MainMenuViewModel.java b/app/src/main/java/com/example/tasktracker/Activities/ViewModels/MainMenuViewModel.java similarity index 93% rename from app/src/main/java/com/example/tasktracker/Activities/MainMenuViewModel.java rename to app/src/main/java/com/example/tasktracker/Activities/ViewModels/MainMenuViewModel.java index 0057f85..9a34039 100644 --- a/app/src/main/java/com/example/tasktracker/Activities/MainMenuViewModel.java +++ b/app/src/main/java/com/example/tasktracker/Activities/ViewModels/MainMenuViewModel.java @@ -1,4 +1,4 @@ -package com.example.tasktracker.Activities; +package com.example.tasktracker.Activities.ViewModels; import android.app.Application; @@ -6,11 +6,9 @@ import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.Observer; import com.example.tasktracker.Answers.Task; import com.example.tasktracker.Api.ApiFactory; -import com.example.tasktracker.Api.TaskRepository; import java.util.ArrayList; import java.util.List; diff --git a/app/src/main/java/com/example/tasktracker/Answers/Task.java b/app/src/main/java/com/example/tasktracker/Answers/Task.java index aad0b36..be003a9 100644 --- a/app/src/main/java/com/example/tasktracker/Answers/Task.java +++ b/app/src/main/java/com/example/tasktracker/Answers/Task.java @@ -30,10 +30,10 @@ public class Task implements Serializable { } @Ignore - public Task(long ID, String TaskName, String TaskDescription, String TaskData) { + public Task(long ID, String TaskName, String TaskDescription, String TaskDate) { this.TaskName = TaskName; this.TaskDescription = TaskDescription; - this.TaskDate = TaskData; + this.TaskDate = TaskDate; this.ID = ID; } diff --git a/app/src/main/java/com/example/tasktracker/Api/ApiService.java b/app/src/main/java/com/example/tasktracker/Api/ApiService.java index 21fcc55..f3cb0d4 100644 --- a/app/src/main/java/com/example/tasktracker/Api/ApiService.java +++ b/app/src/main/java/com/example/tasktracker/Api/ApiService.java @@ -13,6 +13,9 @@ import retrofit2.http.POST; import retrofit2.http.Query; public interface ApiService { + @GET("user") + Single checkToken(@Query("token") String token); + @GET("singin") Single singin(@Query("login") String login, @Query("password") String password); @@ -20,10 +23,13 @@ public interface ApiService { Single singup(@Query("login") String login, @Query("password") String password); @GET("user/task") + Single getTask(@Query("token") String token, @Query("id") long id); + + @GET("user/task/list") Single> getTaskList(@Query("token") String token); - @POST("user/task/add") - Call addTask(@Query("token") String token, @Body Task task); + @POST("user/task/edit") + Call editTask(@Query("token") String token, @Body Task task); @POST("user/task/remove") Call removeTask(@Query("token") String token, @Query("id") long ID); diff --git a/app/src/main/java/com/example/tasktracker/Api/TaskDao.java b/app/src/main/java/com/example/tasktracker/Api/TaskDao.java index 80401e4..df66dee 100644 --- a/app/src/main/java/com/example/tasktracker/Api/TaskDao.java +++ b/app/src/main/java/com/example/tasktracker/Api/TaskDao.java @@ -18,6 +18,9 @@ public interface TaskDao { @Query("SELECT * FROM task_room") LiveData> getTaskList(); + @Query("SELECT * FROM task_room ORDER BY (:id)") + LiveData getTask(long id); + @Query("DELETE FROM task_room") void DropTable(); diff --git a/app/src/main/java/com/example/tasktracker/PublicKeyNames.java b/app/src/main/java/com/example/tasktracker/PublicKeyNames.java new file mode 100644 index 0000000..b23e743 --- /dev/null +++ b/app/src/main/java/com/example/tasktracker/PublicKeyNames.java @@ -0,0 +1,6 @@ +package com.example.tasktracker; + +public abstract class PublicKeyNames { + public static final String TOKEN_LIST = "token_list"; + public static final String TOKEN_KEY = "TOKEN"; +} diff --git a/app/src/main/res/drawable/add.png b/app/src/main/res/drawable/add.png new file mode 100644 index 0000000000000000000000000000000000000000..3d0b46fd486038e4aee47fc204c9ae69f62848cf GIT binary patch literal 17923 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 CIZc58 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/exit.png b/app/src/main/res/drawable/exit.png new file mode 100644 index 0000000000000000000000000000000000000000..a7cb39c36e7a62eebde53ff7999943b23e58ac48 GIT binary patch literal 9197 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_add_new_task.xml b/app/src/main/res/layout/activity_add_new_task.xml index 24547b9..98ef167 100644 --- a/app/src/main/res/layout/activity_add_new_task.xml +++ b/app/src/main/res/layout/activity_add_new_task.xml @@ -21,56 +21,17 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textMultiLine"/> - - - - - - - + android:layout_margin="5sp"/>