This commit is contained in:
Данил
2025-05-14 16:55:49 +07:00
parent a9b9eb1044
commit 9259aaab19
23 changed files with 567 additions and 212 deletions
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+1 -1
View File
@@ -4,7 +4,7 @@ plugins {
android { android {
namespace = "com.example.tasktracker" namespace = "com.example.tasktracker"
compileSdk = 35 compileSdk = 36
defaultConfig { defaultConfig {
applicationId = "com.example.tasktracker" applicationId = "com.example.tasktracker"
+3 -1
View File
@@ -17,7 +17,9 @@
android:theme="@style/Theme.TaskTracker" android:theme="@style/Theme.TaskTracker"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
tools:targetApi="31"> tools:targetApi="31">
<activity
android:name=".Activities.EditTask"
android:exported="false" />
<activity <activity
android:name=".Activities.AddNewTask" android:name=".Activities.AddNewTask"
android:exported="false" /> android:exported="false" />
@@ -1,28 +1,32 @@
package com.example.tasktracker.Activities; package com.example.tasktracker.Activities;
import android.app.DatePickerDialog;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.widget.DatePicker;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import com.example.tasktracker.Activities.ViewModels.AddItemViewModel;
import com.example.tasktracker.Answers.Task; import com.example.tasktracker.Answers.Task;
import com.example.tasktracker.PublicKeyNames;
import com.example.tasktracker.R; import com.example.tasktracker.R;
import com.example.tasktracker.databinding.ActivityAddNewTaskBinding; import com.example.tasktracker.databinding.ActivityAddNewTaskBinding;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import java.util.Random; 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 TAG = "ADD_NEW_TASK";
private static final String TOKEN_KEY = "TOKEN";
private ActivityAddNewTaskBinding binding; private ActivityAddNewTaskBinding binding;
private static String token; private static String token;
private AddItemViewModel viewModel; private AddItemViewModel viewModel;
private String stringDate = "";
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@@ -30,13 +34,20 @@ public class AddNewTask extends AppCompatActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(binding.getRoot()); setContentView(binding.getRoot());
token = getIntent().getStringExtra(TOKEN_KEY); token = getIntent().getStringExtra(PublicKeyNames.TOKEN_KEY);
if(token == null) if(token == null)
{ {
Log.w(TAG, "Token is null"); Log.w(TAG, "Token is null");
return; return;
} }
binding.btnDatePick.setOnClickListener(v->{
DatePickerFragment fragment;
fragment = new DatePickerFragment();
fragment.show(getSupportFragmentManager(), "DATE PICK");
});
viewModel = new ViewModelProvider(this).get(AddItemViewModel.class); viewModel = new ViewModelProvider(this).get(AddItemViewModel.class);
viewModel.getClose().observe(this, new Observer<Boolean>() { viewModel.getClose().observe(this, new Observer<Boolean>() {
@Override @Override
@@ -60,19 +71,18 @@ public class AddNewTask extends AppCompatActivity {
binding.AddTask.setOnClickListener(v->{ binding.AddTask.setOnClickListener(v->{
String name = binding.TaskName.getText().toString(); String name = binding.TaskName.getText().toString();
String description = binding.TaskDescription.getText().toString(); String description = binding.TaskDescription.getText().toString();
String date = getDate();
if(name.isEmpty()) { if(name.isEmpty()) {
Snackbar.make(binding.getRoot(), R.string.snackbar_EnterName, Snackbar.LENGTH_SHORT).show(); Snackbar.make(binding.getRoot(), R.string.snackbar_EnterName, Snackbar.LENGTH_SHORT).show();
return; return;
} }
if(date.isEmpty()) { if(stringDate.isEmpty()) {
Snackbar.make(binding.getRoot(), R.string.snackbar_EnterDate, Snackbar.LENGTH_SHORT).show(); Snackbar.make(binding.getRoot(), R.string.snackbar_EnterDate, Snackbar.LENGTH_SHORT).show();
return; return;
} }
long ID = generateID(name, description, date); long ID = generateID(name, description, stringDate);
Task task = new Task(ID, name, description, date); Task task = new Task(ID, name, description, stringDate);
viewModel.OfflineSaveData(task); viewModel.OfflineSaveData(task);
}); });
} }
@@ -88,7 +98,7 @@ public class AddNewTask extends AppCompatActivity {
binding.AddTask.setOnClickListener(v->{ binding.AddTask.setOnClickListener(v->{
String name = binding.TaskName.getText().toString(); String name = binding.TaskName.getText().toString();
String description = binding.TaskDescription.getText().toString(); String description = binding.TaskDescription.getText().toString();
String date = getDate(); String date = binding.btnDatePick.getText().toString();
if(name.isEmpty()) { if(name.isEmpty()) {
Snackbar.make(binding.getRoot(), R.string.snackbar_EnterName, Snackbar.LENGTH_SHORT).show(); 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) { private long generateID(String name, String Description, String date) {
Random rand = new Random(); Random rand = new Random();
@@ -129,7 +129,15 @@ public class AddNewTask extends AppCompatActivity {
public static Intent getIntent(Context context, String token) { public static Intent getIntent(Context context, String token) {
Intent intent = new Intent(context, AddNewTask.class); Intent intent = new Intent(context, AddNewTask.class);
intent.putExtra(TOKEN_KEY, token); intent.putExtra(PublicKeyNames.TOKEN_KEY, token);
return intent; 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);
}
} }
@@ -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);
}
}
@@ -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<Task>() {
@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<Boolean>() {
@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<String>() {
@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);
}
}
@@ -1,7 +1,9 @@
package com.example.tasktracker.Activities; package com.example.tasktracker.Activities;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
@@ -10,10 +12,13 @@ import androidx.appcompat.app.AppCompatActivity;
import com.example.tasktracker.Answers.LoginAnswer; import com.example.tasktracker.Answers.LoginAnswer;
import com.example.tasktracker.Api.ApiFactory; import com.example.tasktracker.Api.ApiFactory;
import com.example.tasktracker.PublicKeyNames;
import com.example.tasktracker.R; import com.example.tasktracker.R;
import com.example.tasktracker.databinding.ActivityLoginBinding; import com.example.tasktracker.databinding.ActivityLoginBinding;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import java.util.Objects;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.disposables.CompositeDisposable;
@@ -24,7 +29,12 @@ import io.reactivex.rxjava3.schedulers.Schedulers;
public class LoginActivity extends AppCompatActivity { public class LoginActivity extends AppCompatActivity {
private static final String TAG = "LOGIN_ACTIVITY"; private static final String TAG = "LOGIN_ACTIVITY";
private ActivityLoginBinding binding; 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") @SuppressLint("UnsafeIntentLaunch")
@Override @Override
@@ -34,6 +44,33 @@ public class LoginActivity extends AppCompatActivity {
EdgeToEdge.enable(this); EdgeToEdge.enable(this);
setContentView(binding.getRoot()); 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<LoginAnswer>() {
@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<Throwable>() {
@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.buttonSingIn.setOnClickListener(v->{ SingIn(); });
binding.buttonSingUp.setOnClickListener(v->{ SingUp(); }); binding.buttonSingUp.setOnClickListener(v->{ SingUp(); });
@@ -74,6 +111,7 @@ public class LoginActivity extends AppCompatActivity {
} }
String token = loginAnswer.getToken(); String token = loginAnswer.getToken();
sharedPreferences.edit().putString(PublicKeyNames.TOKEN_KEY, token).apply();
OpenMainMenu(token); OpenMainMenu(token);
} }
}, new Consumer<Throwable>() { }, new Consumer<Throwable>() {
@@ -115,6 +153,7 @@ public class LoginActivity extends AppCompatActivity {
} }
String token = loginAnswer.getToken(); String token = loginAnswer.getToken();
sharedPreferences.edit().putString(PublicKeyNames.TOKEN_KEY, token).apply();
OpenMainMenu(token); OpenMainMenu(token);
} }
}, new Consumer<Throwable>() { }, new Consumer<Throwable>() {
@@ -127,6 +166,12 @@ public class LoginActivity extends AppCompatActivity {
compositeDisposable.add(disposable); compositeDisposable.add(disposable);
} }
@Override
protected void onDestroy() {
super.onDestroy();
compositeDisposable.dispose();
}
private void OpenMainMenu(String token) private void OpenMainMenu(String token)
{ {
@SuppressLint("UnsafeIntentLaunch") @SuppressLint("UnsafeIntentLaunch")
@@ -1,7 +1,9 @@
package com.example.tasktracker.Activities; package com.example.tasktracker.Activities;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.text.Editable; import android.text.Editable;
@@ -15,15 +17,16 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.example.tasktracker.Activities.ViewModels.MainMenuViewModel;
import com.example.tasktracker.Answers.Task; import com.example.tasktracker.Answers.Task;
import com.example.tasktracker.Api.ApiFactory; import com.example.tasktracker.Api.ApiFactory;
import com.example.tasktracker.Api.TaskRepository; import com.example.tasktracker.Api.TaskRepository;
import com.example.tasktracker.PublicKeyNames;
import com.example.tasktracker.R; import com.example.tasktracker.R;
import com.example.tasktracker.databinding.ActivityMainMenuBinding; import com.example.tasktracker.databinding.ActivityMainMenuBinding;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -33,14 +36,12 @@ import retrofit2.Response;
public class MainMenu extends AppCompatActivity { public class MainMenu extends AppCompatActivity {
private static final String TAG = "MainMenu"; private static final String TAG = "MainMenu";
private static final String TOKEN_KEY = "TOKEN";
private ActivityMainMenuBinding binding; private ActivityMainMenuBinding binding;
private String token; private String token;
private TaskAdapter taskAdapter; private TaskAdapter taskAdapter;
private MainMenuViewModel viewModel; private MainMenuViewModel viewModel;
private List<Task> taskListCache = new ArrayList<>();
private List<Task> taskListCache;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@@ -48,19 +49,27 @@ public class MainMenu extends AppCompatActivity {
binding = ActivityMainMenuBinding.inflate(getLayoutInflater()); binding = ActivityMainMenuBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot()); setContentView(binding.getRoot());
token = getIntent().getStringExtra(TOKEN_KEY); token = getIntent().getStringExtra(PublicKeyNames.TOKEN_KEY);
if(token == null) if (token == null) {
{
Log.e(TAG, "Token is empty"); Log.e(TAG, "Token is empty");
return; return;
} }
taskAdapter = new TaskAdapter(); taskAdapter = new TaskAdapter();
binding.scrollTask.setAdapter(taskAdapter); binding.scrollTask.setAdapter(taskAdapter);
binding.buttonAddNewTask.setOnClickListener(v->{ binding.buttonAddNewTask.setOnClickListener(v -> {
Intent intent = AddNewTask.getIntent(this, token); Intent intent = AddNewTask.getIntent(this, token);
startActivity(intent); 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); viewModel = new ViewModelProvider(this).get(MainMenuViewModel.class);
binding.findLine.addTextChangedListener(new TextWatcher() { binding.findLine.addTextChangedListener(new TextWatcher() {
@@ -72,8 +81,8 @@ public class MainMenu extends AppCompatActivity {
@Override @Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
String find = binding.findLine.getText().toString(); String find = binding.findLine.getText().toString();
if(find.isEmpty()) { if (find.isEmpty()) {
if(token.equals("null")) { if (token.equals("null")) {
TaskRepository.newInstance(getApplication()).taskDao().getTaskList().observe(MainMenu.this, new Observer<List<Task>>() { TaskRepository.newInstance(getApplication()).taskDao().getTaskList().observe(MainMenu.this, new Observer<List<Task>>() {
@Override @Override
public void onChanged(List<Task> tasks) { public void onChanged(List<Task> tasks) {
@@ -81,8 +90,7 @@ public class MainMenu extends AppCompatActivity {
taskAdapter.setTaskList(tasks); taskAdapter.setTaskList(tasks);
} }
}); });
} } else {
else {
viewModel.OnlineUpdateList(token); viewModel.OnlineUpdateList(token);
} }
} }
@@ -112,8 +120,20 @@ public class MainMenu extends AppCompatActivity {
} }
}); });
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 // offline
if(token.equals("null")) { if (token.equals("null")) {
Offline(); Offline();
} }
//online //online
@@ -122,7 +142,7 @@ public class MainMenu extends AppCompatActivity {
} }
} }
public void Offline() { public void Offline () {
viewModel.getOnLoad().observe(this, new Observer<List<Task>>() { viewModel.getOnLoad().observe(this, new Observer<List<Task>>() {
@Override @Override
public void onChanged(List<Task> tasks) { public void onChanged(List<Task> tasks) {
@@ -149,6 +169,12 @@ public class MainMenu extends AppCompatActivity {
@Override @Override
public void run() { public void run() {
TaskRepository.newInstance(getApplication()).taskDao().delete(task); 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(); }).start();
taskAdapter.removeItemByPosition(position); taskAdapter.removeItemByPosition(position);
@@ -157,7 +183,7 @@ public class MainMenu extends AppCompatActivity {
helper.attachToRecyclerView(binding.scrollTask); helper.attachToRecyclerView(binding.scrollTask);
} }
private void Online() { private void Online () {
viewModel.getOnLoad().observe(this, new Observer<List<Task>>() { viewModel.getOnLoad().observe(this, new Observer<List<Task>>() {
@Override @Override
@@ -207,9 +233,9 @@ public class MainMenu extends AppCompatActivity {
} }
@Override @Override
protected void onResume() { protected void onResume () {
super.onResume(); super.onResume();
if(token.equals("null")) { if (token.equals("null")) {
TaskRepository.newInstance(getApplication()).taskDao().getTaskList().observe(this, new Observer<List<Task>>() { TaskRepository.newInstance(getApplication()).taskDao().getTaskList().observe(this, new Observer<List<Task>>() {
@Override @Override
public void onChanged(List<Task> tasks) { public void onChanged(List<Task> tasks) {
@@ -217,16 +243,15 @@ public class MainMenu extends AppCompatActivity {
taskAdapter.setTaskList(tasks); taskAdapter.setTaskList(tasks);
} }
}); });
} } else {
else {
viewModel.OnlineUpdateList(token); viewModel.OnlineUpdateList(token);
} }
} }
public static Intent getIntent(Context context, String token) { public static Intent getIntent (Context context, String token){
Intent intent = new Intent(context, MainMenu.class); Intent intent = new Intent(context, MainMenu.class);
intent.putExtra(TOKEN_KEY, token); intent.putExtra(PublicKeyNames.TOKEN_KEY, token);
return intent; return intent;
} }
} }
@@ -1,4 +1,4 @@
package com.example.tasktracker.Activities; package com.example.tasktracker.Activities.ViewModels;
import android.app.Application; import android.app.Application;
import android.util.Log; import android.util.Log;
@@ -7,7 +7,6 @@ import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import com.example.tasktracker.Answers.Task; import com.example.tasktracker.Answers.Task;
import com.example.tasktracker.Api.ApiFactory; import com.example.tasktracker.Api.ApiFactory;
@@ -38,7 +37,7 @@ public class AddItemViewModel extends AndroidViewModel {
public void OnlineSaveData(Task task, String token) { public void OnlineSaveData(Task task, String token) {
Call<Void> send = ApiFactory.getApiService().addTask(token, task); Call<Void> send = ApiFactory.getApiService().editTask(token, task);
send.enqueue(new Callback<Void>() { send.enqueue(new Callback<Void>() {
@Override @Override
public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) { public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) {
@@ -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<Boolean> liveDataSave = new MutableLiveData<>();
private final MutableLiveData<String> liveDataFail = new MutableLiveData<>();
private final MutableLiveData<Task> 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<Void> send = ApiFactory.getApiService().editTask(token, task);
send.enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) {
Log.d(TAG, "Task update successfully");
liveDataSave.postValue(true);
}
@Override
public void onFailure(@NonNull Call<Void> 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<Task>() {
@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<Task>() {
@Override
public void accept(Task task) throws Throwable {
liveDataLoad.postValue(task);
}
}, new Consumer<Throwable>() {
@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<Task> isLoading() {
return liveDataLoad;
}
public LiveData<String> getLiveDataFail() {
return liveDataFail;
}
public LiveData<Boolean> getClose() {
return liveDataSave;
}
}
@@ -1,4 +1,4 @@
package com.example.tasktracker.Activities; package com.example.tasktracker.Activities.ViewModels;
import android.app.Application; import android.app.Application;
@@ -6,11 +6,9 @@ import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import com.example.tasktracker.Answers.Task; import com.example.tasktracker.Answers.Task;
import com.example.tasktracker.Api.ApiFactory; import com.example.tasktracker.Api.ApiFactory;
import com.example.tasktracker.Api.TaskRepository;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -30,10 +30,10 @@ public class Task implements Serializable {
} }
@Ignore @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.TaskName = TaskName;
this.TaskDescription = TaskDescription; this.TaskDescription = TaskDescription;
this.TaskDate = TaskData; this.TaskDate = TaskDate;
this.ID = ID; this.ID = ID;
} }
@@ -13,6 +13,9 @@ import retrofit2.http.POST;
import retrofit2.http.Query; import retrofit2.http.Query;
public interface ApiService { public interface ApiService {
@GET("user")
Single<LoginAnswer> checkToken(@Query("token") String token);
@GET("singin") @GET("singin")
Single<LoginAnswer> singin(@Query("login") String login, @Query("password") String password); Single<LoginAnswer> singin(@Query("login") String login, @Query("password") String password);
@@ -20,10 +23,13 @@ public interface ApiService {
Single<LoginAnswer> singup(@Query("login") String login, @Query("password") String password); Single<LoginAnswer> singup(@Query("login") String login, @Query("password") String password);
@GET("user/task") @GET("user/task")
Single<Task> getTask(@Query("token") String token, @Query("id") long id);
@GET("user/task/list")
Single<ArrayList<Task>> getTaskList(@Query("token") String token); Single<ArrayList<Task>> getTaskList(@Query("token") String token);
@POST("user/task/add") @POST("user/task/edit")
Call<Void> addTask(@Query("token") String token, @Body Task task); Call<Void> editTask(@Query("token") String token, @Body Task task);
@POST("user/task/remove") @POST("user/task/remove")
Call<Void> removeTask(@Query("token") String token, @Query("id") long ID); Call<Void> removeTask(@Query("token") String token, @Query("id") long ID);
@@ -18,6 +18,9 @@ public interface TaskDao {
@Query("SELECT * FROM task_room") @Query("SELECT * FROM task_room")
LiveData<List<Task>> getTaskList(); LiveData<List<Task>> getTaskList();
@Query("SELECT * FROM task_room ORDER BY (:id)")
LiveData<Task> getTask(long id);
@Query("DELETE FROM task_room") @Query("DELETE FROM task_room")
void DropTable(); void DropTable();
@@ -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";
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

@@ -21,56 +21,17 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textMultiLine"/> android:inputType="textMultiLine"/>
<LinearLayout <Button
android:layout_width="match_parent" android:id="@+id/btnDatePick"
android:text="@string/button_DefaultData"
android:layout_width="200sp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"> android:layout_margin="5sp"/>
<EditText
android:id="@+id/day"
android:hint="@string/hint_Day"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="numberDecimal"/>
<EditText
android:id="@+id/month"
android:hint="@string/hint_Month"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="numberDecimal"/>
<EditText
android:id="@+id/year"
android:hint="@string/hint_Yar"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="numberDecimal"/>
<EditText
android:id="@+id/hour"
android:hint="@string/hint_Hour"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="numberDecimal"/>
<EditText
android:id="@+id/minute"
android:hint="@string/hint_Minute"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="numberDecimal"/>
</LinearLayout>
<Button <Button
android:id="@+id/AddTask" android:id="@+id/AddTask"
android:text="@string/button_AddTask" android:text="@string/button_AddTask"
android:textSize="20sp" android:textSize="20sp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"
android:layout_margin="5sp"/>
</LinearLayout> </LinearLayout>
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Activities.AddNewTask"
android:orientation="vertical">
<EditText
android:id="@+id/TaskName"
android:hint="@string/hint_TaskName"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"/>
<EditText
android:id="@+id/TaskDescription"
android:hint="@string/hint_TaskDescription"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"/>
<Button
android:id="@+id/btnDatePick"
android:text="@string/button_DefaultData"
android:layout_width="200sp"
android:layout_height="wrap_content"
android:layout_margin="5sp"/>
<Button
android:id="@+id/btnEditTask"
android:text="@string/button_editTask"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5sp"/>
</LinearLayout>
+10 -2
View File
@@ -8,7 +8,6 @@
android:orientation="vertical" android:orientation="vertical"
tools:context=".Activities.MainMenu"> tools:context=".Activities.MainMenu">
<EditText <EditText
android:id="@+id/findLine" android:id="@+id/findLine"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -29,9 +28,18 @@
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@id/findLine"/> app:layout_constraintTop_toBottomOf="@id/findLine"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/button_SingOut"
android:src="@drawable/exit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/button_addNewTask"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="20sp"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/button_addNewTask" android:id="@+id/button_addNewTask"
android:src="@android:drawable/ic_menu_add" android:src="@drawable/add"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
+2 -3
View File
@@ -9,7 +9,7 @@
<string name="button_NO">No</string> <string name="button_NO">No</string>
<string name="hint_Login">Login</string> <string name="hint_Login">Login</string>
<string name="hint_Password">Password</string> <string name="hint_Password">Password</string>
<string name="hint_Find">Task name</string> <string name="hint_Find">Name or description</string>
<string name="hint_TaskName">Task name</string> <string name="hint_TaskName">Task name</string>
<string name="hint_TaskDescription">Description</string> <string name="hint_TaskDescription">Description</string>
<string name="hint_Minute">Minute</string> <string name="hint_Minute">Minute</string>
@@ -22,8 +22,7 @@
<string name="snackbar_EnterName">Enter task name</string> <string name="snackbar_EnterName">Enter task name</string>
<string name="snackbar_EnterDate">Enter task date</string> <string name="snackbar_EnterDate">Enter task date</string>
<string name="snackbar_DataBaseError">Something went wrong.</string> <string name="snackbar_DataBaseError">Something went wrong.</string>
<string name="title_AlertRemoveTask">Remove task?</string> <string name="button_editTask">Edit task</string>
<string name="message_RemoveTask">Task will remove on all devices.</string>
<string name="button_YES">Yes</string> <string name="button_YES">Yes</string>
<string name="hint_Day">Day</string> <string name="hint_Day">Day</string>
<string name="hint_Month">Month</string> <string name="hint_Month">Month</string>
+2 -3
View File
@@ -9,7 +9,7 @@
<string name="button_NO">Нет</string> <string name="button_NO">Нет</string>
<string name="hint_Login">Логин</string> <string name="hint_Login">Логин</string>
<string name="hint_Password">Пароль</string> <string name="hint_Password">Пароль</string>
<string name="hint_Find">Название задачи</string> <string name="hint_Find">Название или описание</string>
<string name="hint_TaskName">Название задачи</string> <string name="hint_TaskName">Название задачи</string>
<string name="hint_TaskDescription">Описание</string> <string name="hint_TaskDescription">Описание</string>
<string name="hint_Minute">Минута</string> <string name="hint_Minute">Минута</string>
@@ -22,8 +22,7 @@
<string name="snackbar_EnterName">Введите назвние</string> <string name="snackbar_EnterName">Введите назвние</string>
<string name="snackbar_EnterDate">Введите дату</string> <string name="snackbar_EnterDate">Введите дату</string>
<string name="snackbar_DataBaseError">Что-то пошло не так</string> <string name="snackbar_DataBaseError">Что-то пошло не так</string>
<string name="title_AlertRemoveTask">Удалить задачу?</string> <string name="button_editTask">Редакировать</string>
<string name="message_RemoveTask">Задача удалится на всех устройствах.</string>
<string name="button_YES">Да</string> <string name="button_YES">Да</string>
<string name="hint_Day">День</string> <string name="hint_Day">День</string>
<string name="hint_Month">Месяц</string> <string name="hint_Month">Месяц</string>
+3 -6
View File
@@ -7,13 +7,15 @@
<string name="button_offline">Offline</string> <string name="button_offline">Offline</string>
<string name="button_Sort">Sort</string> <string name="button_Sort">Sort</string>
<string name="button_AddTask">Add task</string> <string name="button_AddTask">Add task</string>
<string name="button_editTask">Edit task</string>
<string name="button_YES">Yes</string> <string name="button_YES">Yes</string>
<string name="button_NO">No</string> <string name="button_NO">No</string>
<string name="button_DefaultData" translatable="false">DD/MM/YEAR</string>
<!-- Hints --> <!-- Hints -->
<string name="hint_Login">Login</string> <string name="hint_Login">Login</string>
<string name="hint_Password">Password</string> <string name="hint_Password">Password</string>
<string name="hint_Find">Task name</string> <string name="hint_Find">Name or description</string>
<string name="hint_TaskName">Task name</string> <string name="hint_TaskName">Task name</string>
<string name="hint_TaskDescription">Description</string> <string name="hint_TaskDescription">Description</string>
<string name="hint_Day">Day</string> <string name="hint_Day">Day</string>
@@ -33,9 +35,4 @@
<string name="snackbar_EnterDate">Enter task date</string> <string name="snackbar_EnterDate">Enter task date</string>
<string name="snackbar_DataBaseError">Something went wrong.</string> <string name="snackbar_DataBaseError">Something went wrong.</string>
<!-- Titles -->
<string name="title_AlertRemoveTask">Remove task?</string>
<!-- Messages -->
<string name="message_RemoveTask">Task will remove on all devices.</string>
</resources> </resources>