From d88094b0cfcdd1b221cd2d70ccc50762df31550d Mon Sep 17 00:00:00 2001 From: CappielloAntonio Date: Mon, 9 Aug 2021 17:55:30 +0200 Subject: [PATCH] Revised the gestures of the server adapter --- .../play/adapter/ServerAdapter.java | 3 ++ .../play/database/AppDatabase.java | 2 +- .../play/database/dao/ServerDao.java | 6 +++ .../cappielloantonio/play/model/Server.java | 31 ++++++++++++- .../play/repository/ServerRepository.java | 45 +++++++++++++++++++ .../play/repository/SystemRepository.java | 21 +++++---- .../play/subsonic/Subsonic.java | 4 +- .../play/ui/fragment/LoginFragment.java | 33 ++++++++++++-- .../fragment/dialog/ServerSignupDialog.java | 39 ++++++++++++++-- .../play/viewmodel/LoginViewModel.java | 21 ++++++++- .../main/res/layout/dialog_server_signup.xml | 11 ++++- 11 files changed, 195 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/play/adapter/ServerAdapter.java b/app/src/main/java/com/cappielloantonio/play/adapter/ServerAdapter.java index c453461e..f5b594f3 100644 --- a/app/src/main/java/com/cappielloantonio/play/adapter/ServerAdapter.java +++ b/app/src/main/java/com/cappielloantonio/play/adapter/ServerAdapter.java @@ -1,6 +1,7 @@ package com.cappielloantonio.play.adapter; import android.content.Context; +import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -8,6 +9,7 @@ import android.widget.TextView; import android.widget.Toast; import androidx.fragment.app.FragmentManager; +import androidx.navigation.Navigation; import androidx.recyclerview.widget.RecyclerView; import com.cappielloantonio.play.App; @@ -17,6 +19,7 @@ import com.cappielloantonio.play.model.Server; import com.cappielloantonio.play.model.Song; import com.cappielloantonio.play.repository.SystemRepository; import com.cappielloantonio.play.ui.activity.MainActivity; +import com.cappielloantonio.play.ui.fragment.dialog.ServerSignupDialog; import com.cappielloantonio.play.util.PreferenceUtil; import java.util.ArrayList; diff --git a/app/src/main/java/com/cappielloantonio/play/database/AppDatabase.java b/app/src/main/java/com/cappielloantonio/play/database/AppDatabase.java index a2cd82e8..69e63105 100644 --- a/app/src/main/java/com/cappielloantonio/play/database/AppDatabase.java +++ b/app/src/main/java/com/cappielloantonio/play/database/AppDatabase.java @@ -15,7 +15,7 @@ import com.cappielloantonio.play.model.Queue; import com.cappielloantonio.play.model.RecentSearch; import com.cappielloantonio.play.model.Server; -@Database(entities = {Queue.class, Server.class, RecentSearch.class, Download.class}, version = 12, exportSchema = false) +@Database(entities = {Queue.class, Server.class, RecentSearch.class, Download.class}, version = 13, exportSchema = false) public abstract class AppDatabase extends RoomDatabase { private static final String TAG = "AppDatabase"; diff --git a/app/src/main/java/com/cappielloantonio/play/database/dao/ServerDao.java b/app/src/main/java/com/cappielloantonio/play/database/dao/ServerDao.java index cff8d416..02a4a66e 100644 --- a/app/src/main/java/com/cappielloantonio/play/database/dao/ServerDao.java +++ b/app/src/main/java/com/cappielloantonio/play/database/dao/ServerDao.java @@ -20,6 +20,12 @@ public interface ServerDao { @Insert(onConflict = OnConflictStrategy.REPLACE) void insert(Server server); + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertAll(List servers); + @Delete void delete(Server server); + + @Query("DELETE FROM server") + void deleteAll(); } \ No newline at end of file diff --git a/app/src/main/java/com/cappielloantonio/play/model/Server.java b/app/src/main/java/com/cappielloantonio/play/model/Server.java index 6dce85cd..281c4a5f 100644 --- a/app/src/main/java/com/cappielloantonio/play/model/Server.java +++ b/app/src/main/java/com/cappielloantonio/play/model/Server.java @@ -1,12 +1,15 @@ package com.cappielloantonio.play.model; +import android.os.Parcel; +import android.os.Parcelable; + import androidx.annotation.NonNull; import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.PrimaryKey; @Entity(tableName = "server") -public class Server { +public class Server implements Parcelable { @NonNull @PrimaryKey @ColumnInfo(name = "id") @@ -96,4 +99,30 @@ public class Server { public void setTimestamp(long timestamp) { this.timestamp = timestamp; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(serverId); + dest.writeString(serverName); + dest.writeString(username); + dest.writeString(address); + dest.writeString(token); + dest.writeString(salt); + dest.writeLong(timestamp); + } + + protected Server(Parcel in) { + this.serverId = in.readString(); + this.serverName = in.readString(); + this.username = in.readString(); + this.address = in.readString(); + this.token = in.readString(); + this.salt = in.readString(); + this.timestamp = in.readLong(); + } } diff --git a/app/src/main/java/com/cappielloantonio/play/repository/ServerRepository.java b/app/src/main/java/com/cappielloantonio/play/repository/ServerRepository.java index 32c511a4..1c9a4d0e 100644 --- a/app/src/main/java/com/cappielloantonio/play/repository/ServerRepository.java +++ b/app/src/main/java/com/cappielloantonio/play/repository/ServerRepository.java @@ -5,8 +5,11 @@ import android.app.Application; import androidx.lifecycle.LiveData; import com.cappielloantonio.play.database.AppDatabase; +import com.cappielloantonio.play.database.dao.QueueDao; import com.cappielloantonio.play.database.dao.ServerDao; import com.cappielloantonio.play.model.Server; +import com.cappielloantonio.play.model.Song; +import com.cappielloantonio.play.util.QueueUtil; import java.util.List; @@ -38,6 +41,20 @@ public class ServerRepository { thread.start(); } + public void order(List servers) { + try { + final Thread delete = new Thread(new DeleteAllThreadSafe(serverDao)); + final Thread insertAll = new Thread(new InsertAllThreadSafe(serverDao, servers)); + + delete.start(); + delete.join(); + insertAll.start(); + insertAll.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + private static class InsertThreadSafe implements Runnable { private ServerDao serverDao; private Server server; @@ -67,4 +84,32 @@ public class ServerRepository { serverDao.delete(server); } } + + private static class InsertAllThreadSafe implements Runnable { + private ServerDao serverDao; + private List servers; + + public InsertAllThreadSafe(ServerDao queueDao, List servers) { + this.serverDao = queueDao; + this.servers = servers; + } + + @Override + public void run() { + serverDao.insertAll(servers); + } + } + + private static class DeleteAllThreadSafe implements Runnable { + private ServerDao serverDao; + + public DeleteAllThreadSafe(ServerDao serverDao) { + this.serverDao = serverDao; + } + + @Override + public void run() { + serverDao.deleteAll(); + } + } } diff --git a/app/src/main/java/com/cappielloantonio/play/repository/SystemRepository.java b/app/src/main/java/com/cappielloantonio/play/repository/SystemRepository.java index 8bcb9869..eb60ff3f 100644 --- a/app/src/main/java/com/cappielloantonio/play/repository/SystemRepository.java +++ b/app/src/main/java/com/cappielloantonio/play/repository/SystemRepository.java @@ -25,14 +25,19 @@ public class SystemRepository { .enqueue(new Callback() { @Override public void onResponse(Call call, retrofit2.Response response) { - if (response.body().getStatus().getValue().equals(ResponseStatus.FAILED)) { - callback.onError(new Exception(response.body().getError().getCode().getValue() + " - " + response.body().getError().getMessage())); - } else if (response.body().getStatus().getValue().equals(ResponseStatus.OK)) { - String salt = response.raw().request().url().queryParameter("s"); - String token = response.raw().request().url().queryParameter("t"); - callback.onSuccess(token, salt); - } else { - callback.onError(new Exception("Empty response")); + if(response.body() != null) { + if (response.body().getStatus().getValue().equals(ResponseStatus.FAILED)) { + callback.onError(new Exception(response.body().getError().getCode().getValue() + " - " + response.body().getError().getMessage())); + } else if (response.body().getStatus().getValue().equals(ResponseStatus.OK)) { + String salt = response.raw().request().url().queryParameter("s"); + String token = response.raw().request().url().queryParameter("t"); + callback.onSuccess(token, salt); + } else { + callback.onError(new Exception("Empty response")); + } + } + else { + callback.onError(new Exception(String.valueOf(response.code()))); } } diff --git a/app/src/main/java/com/cappielloantonio/play/subsonic/Subsonic.java b/app/src/main/java/com/cappielloantonio/play/subsonic/Subsonic.java index 0df334b3..309c1df9 100644 --- a/app/src/main/java/com/cappielloantonio/play/subsonic/Subsonic.java +++ b/app/src/main/java/com/cappielloantonio/play/subsonic/Subsonic.java @@ -84,7 +84,9 @@ public class Subsonic { } public String getUrl() { - return preferences.getServerUrl() + "/rest/"; + String url = preferences.getServerUrl() + "/rest/"; + + return url.replace("//rest","/rest"); } public Map getParams() { diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/LoginFragment.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/LoginFragment.java index d3e09a00..6ef8b37d 100644 --- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/LoginFragment.java +++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/LoginFragment.java @@ -20,7 +20,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.cappielloantonio.play.R; import com.cappielloantonio.play.adapter.ServerAdapter; import com.cappielloantonio.play.databinding.FragmentLoginBinding; -import com.cappielloantonio.play.service.MusicPlayerRemote; import com.cappielloantonio.play.ui.activity.MainActivity; import com.cappielloantonio.play.ui.fragment.dialog.ServerSignupDialog; import com.cappielloantonio.play.viewmodel.LoginViewModel; @@ -36,6 +35,8 @@ public class LoginFragment extends Fragment { private ServerAdapter serverAdapter; + private ItemTouchHelper itemTouchHelper; + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -99,7 +100,7 @@ public class LoginFragment extends Fragment { } }); - new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT) { + new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { int originalPosition = -1; int fromPosition = -1; int toPosition = -1; @@ -118,10 +119,34 @@ public class LoginFragment extends Fragment { return false; } + @Override + public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + + loginViewModel.orderServer(serverAdapter.getItems()); + + originalPosition = -1; + fromPosition = -1; + toPosition = -1; + } + @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { - loginViewModel.deleteServer(serverAdapter.getItem(viewHolder.getBindingAdapterPosition())); - bind.serverListRecyclerView.getAdapter().notifyItemRemoved(viewHolder.getBindingAdapterPosition()); + switch (direction) { + case ItemTouchHelper.LEFT: + loginViewModel.deleteServer(serverAdapter.getItem(viewHolder.getBindingAdapterPosition())); + break; + case ItemTouchHelper.RIGHT: + Bundle bundle = new Bundle(); + bundle.putParcelable("server_object", serverAdapter.getItem(viewHolder.getBindingAdapterPosition())); + + ServerSignupDialog dialog = new ServerSignupDialog(); + dialog.setArguments(bundle); + dialog.show(activity.getSupportFragmentManager(), null); + + bind.serverListRecyclerView.getAdapter().notifyDataSetChanged(); + break; + } } } ).attachToRecyclerView(bind.serverListRecyclerView); diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/dialog/ServerSignupDialog.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/dialog/ServerSignupDialog.java index 5431089d..b77df364 100644 --- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/dialog/ServerSignupDialog.java +++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/dialog/ServerSignupDialog.java @@ -39,6 +39,7 @@ public class ServerSignupDialog extends DialogFragment { private String username; private String password; private String server; + private boolean directAccess = false; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { @@ -54,7 +55,8 @@ public class ServerSignupDialog extends DialogFragment { builder.setView(bind.getRoot()) .setTitle("Add server") - .setPositiveButton("Enter", (dialog, id) -> { }) + .setNeutralButton("Delete", (dialog, id) -> { }) + .setPositiveButton("Save", (dialog, id) -> { }) .setNegativeButton("Cancel", (dialog, id) -> dialog.cancel()); return builder.create(); @@ -63,6 +65,29 @@ public class ServerSignupDialog extends DialogFragment { @Override public void onStart() { super.onStart(); + + setServerInfo(); + setButtonAction(); + } + + private void setServerInfo() { + if (getArguments() != null) { + loginViewModel.setServerToEdit(getArguments().getParcelable("server_object")); + + if (loginViewModel.getServerToEdit() != null) { + bind.serverNameTextView.setText(loginViewModel.getServerToEdit().getServerName()); + bind.usernameTextView.setText(loginViewModel.getServerToEdit().getUsername()); + bind.passwordTextView.setText(""); + bind.serverTextView.setText(loginViewModel.getServerToEdit().getAddress()); + bind.directAccessCheckbox.setChecked(false); + } + } else { + loginViewModel.setServerToEdit(null); + } + } + + private void setButtonAction() { + ((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_NEUTRAL).setTextColor(getResources().getColor(R.color.colorAccent, null)); ((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(getResources().getColor(R.color.colorAccent, null)); ((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(getResources().getColor(R.color.colorAccent, null)); @@ -70,9 +95,14 @@ public class ServerSignupDialog extends DialogFragment { if (validateInput()) { saveServerPreference(server, username, password, null, null); authenticate(); - ((AlertDialog) Objects.requireNonNull(getDialog())).dismiss(); + Objects.requireNonNull(getDialog()).dismiss(); } }); + + ((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> { + loginViewModel.deleteServer(null); + Objects.requireNonNull(getDialog()).dismiss(); + }); } private boolean validateInput() { @@ -80,6 +110,7 @@ public class ServerSignupDialog extends DialogFragment { username = bind.usernameTextView.getText().toString().trim(); password = bind.passwordTextView.getText().toString(); server = bind.serverTextView.getText().toString().trim(); + directAccess = bind.directAccessCheckbox.isChecked(); if (TextUtils.isEmpty(serverName)) { bind.serverNameTextView.setError("Required"); @@ -110,7 +141,7 @@ public class ServerSignupDialog extends DialogFragment { @Override public void onSuccess(String token, String salt) { saveServerPreference(null, null, null, token, salt); - enter(); + if (directAccess) enter(); } }); } @@ -125,7 +156,7 @@ public class ServerSignupDialog extends DialogFragment { if (password != null) PreferenceUtil.getInstance(context).setPassword(password); if (token != null && salt != null) { - String serverID = UUID.randomUUID().toString(); + String serverID = loginViewModel.getServerToEdit() != null ? loginViewModel.getServerToEdit().getServerId() : UUID.randomUUID().toString(); PreferenceUtil.getInstance(context).setPassword(null); PreferenceUtil.getInstance(context).setToken(token); diff --git a/app/src/main/java/com/cappielloantonio/play/viewmodel/LoginViewModel.java b/app/src/main/java/com/cappielloantonio/play/viewmodel/LoginViewModel.java index c091b631..e9e5f0ee 100644 --- a/app/src/main/java/com/cappielloantonio/play/viewmodel/LoginViewModel.java +++ b/app/src/main/java/com/cappielloantonio/play/viewmodel/LoginViewModel.java @@ -12,6 +12,7 @@ import com.cappielloantonio.play.App; import com.cappielloantonio.play.interfaces.MediaCallback; import com.cappielloantonio.play.model.Album; import com.cappielloantonio.play.model.Server; +import com.cappielloantonio.play.model.Song; import com.cappielloantonio.play.repository.AlbumRepository; import com.cappielloantonio.play.repository.ServerRepository; import com.cappielloantonio.play.subsonic.models.AlbumID3; @@ -27,6 +28,7 @@ import retrofit2.Callback; public class LoginViewModel extends AndroidViewModel { private ServerRepository serverRepository; + private Server toEdit = null; public LoginViewModel(@NonNull Application application) { super(application); @@ -43,6 +45,23 @@ public class LoginViewModel extends AndroidViewModel { } public void deleteServer(Server server) { - serverRepository.delete(server); + if(server != null) { + serverRepository.delete(server); + } + else if(toEdit != null) { + serverRepository.delete(toEdit); + } + } + + public void orderServer(List servers) { + serverRepository.order(servers); + } + + public void setServerToEdit(Server server) { + toEdit = server; + } + + public Server getServerToEdit() { + return toEdit; } } diff --git a/app/src/main/res/layout/dialog_server_signup.xml b/app/src/main/res/layout/dialog_server_signup.xml index d5c155a3..3f9eb0e9 100644 --- a/app/src/main/res/layout/dialog_server_signup.xml +++ b/app/src/main/res/layout/dialog_server_signup.xml @@ -100,6 +100,15 @@ android:inputType="textNoSuggestions" android:text="http://192.168.1.81:4533" android:textCursorDrawable="@null"/> - + + \ No newline at end of file