Revised the gestures of the server adapter

This commit is contained in:
CappielloAntonio 2021-08-09 17:55:30 +02:00
parent 642c41f0c0
commit d88094b0cf
11 changed files with 195 additions and 21 deletions

View file

@ -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;

View file

@ -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";

View file

@ -20,6 +20,12 @@ public interface ServerDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Server server);
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAll(List<Server> servers);
@Delete
void delete(Server server);
@Query("DELETE FROM server")
void deleteAll();
}

View file

@ -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();
}
}

View file

@ -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<Server> 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<Server> servers;
public InsertAllThreadSafe(ServerDao queueDao, List<Server> 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();
}
}
}

View file

@ -25,14 +25,19 @@ public class SystemRepository {
.enqueue(new Callback<SubsonicResponse>() {
@Override
public void onResponse(Call<SubsonicResponse> call, retrofit2.Response<SubsonicResponse> 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())));
}
}

View file

@ -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<String, String> getParams() {

View file

@ -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);

View file

@ -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);

View file

@ -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<Server> servers) {
serverRepository.order(servers);
}
public void setServerToEdit(Server server) {
toEdit = server;
}
public Server getServerToEdit() {
return toEdit;
}
}

View file

@ -100,6 +100,15 @@
android:inputType="textNoSuggestions"
android:text="http://192.168.1.81:4533"
android:textCursorDrawable="@null"/>
</com.google.android.material.textfield.TextInputLayout>
<CheckBox
android:id="@+id/direct_access_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="24dp"
android:text="Direct access"
android:onClick="onCheckboxClicked"/>
</LinearLayout>