undo delete client

This commit is contained in:
badaix 2016-01-17 14:16:18 +01:00
parent d014e79ad0
commit dd020b0b6d
8 changed files with 133 additions and 85 deletions

View file

@ -41,10 +41,7 @@ public class ClientInfoItem extends LinearLayout implements SeekBar.OnSeekBarCha
}
private void update() {
if (!clientInfo.getName().isEmpty())
title.setText(clientInfo.getName());
else
title.setText(clientInfo.getHost());
title.setText(clientInfo.getVisibleName());
title.setEnabled(clientInfo.isConnected());
volumeSeekBar.setProgress(clientInfo.getVolume().getPercent());
if (clientInfo.getVolume().isMuted())

View file

@ -5,8 +5,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.media.AudioManager;
import android.net.Uri;
import android.net.nsd.NsdManager;
@ -14,6 +12,9 @@ import android.net.nsd.NsdServiceInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.design.widget.Snackbar;
import android.support.design.widget.Snackbar.Callback;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
@ -26,7 +27,6 @@ import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
@ -40,9 +40,6 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
private static final String TAG = "Main";
boolean bound = false;
private TextView tvInfo;
private CheckBox cbScreenWakelock;
private ListView lvClient;
private MenuItem miStartStop = null;
private NsdManager.DiscoveryListener mDiscoveryListener;
private NsdManager mNsdManager = null;
@ -82,8 +79,8 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvInfo = (TextView) findViewById(R.id.tvInfo);
cbScreenWakelock = (CheckBox) findViewById(R.id.cbScreenWakelock);
TextView tvInfo = (TextView) findViewById(R.id.tvInfo);
CheckBox cbScreenWakelock = (CheckBox) findViewById(R.id.cbScreenWakelock);
cbScreenWakelock.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
@ -94,8 +91,6 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
}
});
lvClient = (ListView) findViewById(R.id.lvClient);
AudioManager audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
String rate = audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
@ -104,6 +99,7 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
}
clientInfoAdapter = new ClientInfoAdapter(this, this);
ListView lvClient = (ListView) findViewById(R.id.lvClient);
lvClient.setAdapter(clientInfoAdapter);
getSupportActionBar().setSubtitle("Host: no Snapserver found");
@ -175,6 +171,7 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
i.putExtra(SnapclientService.EXTRA_HOST, host);
i.putExtra(SnapclientService.EXTRA_PORT, port);
i.setAction(SnapclientService.ACTION_START);
startService(i);
}
@ -209,7 +206,9 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
getSupportActionBar().setSubtitle(text);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null)
actionBar.setSubtitle(text);
}
});
}
@ -361,9 +360,31 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
}
@Override
public void onDeleteClicked(ClientInfoItem clientInfoItem) {
remoteControl.delete(clientInfoItem.getClientInfo());
clientInfoAdapter.removeClient(clientInfoItem.getClientInfo());
public void onDeleteClicked(final ClientInfoItem clientInfoItem) {
final ClientInfo clientInfo = clientInfoItem.getClientInfo();
clientInfo.setDeleted(true);
clientInfoAdapter.update();
Snackbar mySnackbar = Snackbar.make(findViewById(R.id.myCoordinatorLayout),
getString(R.string.client_deleted, clientInfo.getVisibleName()),
Snackbar.LENGTH_SHORT);
mySnackbar.setAction(R.string.undo_string, new View.OnClickListener() {
@Override
public void onClick(View v) {
clientInfo.setDeleted(false);
clientInfoAdapter.update();
}
});
mySnackbar.setCallback(new Callback() {
@Override
public void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
if (event != DISMISS_EVENT_ACTION) {
remoteControl.delete(clientInfo);
clientInfoAdapter.removeClient(clientInfo);
}
}
});
mySnackbar.show();
}
@Override
@ -409,7 +430,7 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
@Override
public void onServerInfo(RemoteControl remoteControl, ServerInfo serverInfo) {
clientInfoAdapter.update(serverInfo);
clientInfoAdapter.updateServer(serverInfo);
}
private class ClientInfoAdapter extends ArrayAdapter<ClientInfo> {
@ -440,29 +461,36 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
return clientInfoItem;
}
public void updateClient(final ClientInfo clientInfo) {
if (serverInfo.addClient(clientInfo))
update(null);
}
public void removeClient(final ClientInfo clientInfo) {
Log.d(TAG, "removeClient: " + clientInfo.getMac());
if (serverInfo.removeClient(clientInfo)) {
if ((clientInfo != null) && serverInfo.removeClient(clientInfo)) {
Log.d(TAG, "removeClient 1: " + clientInfo.getMac());
update(null);
update();
}
}
public void update(final ServerInfo serverInfo) {
if (serverInfo != null)
public void updateClient(final ClientInfo clientInfo) {
Log.d(TAG, "updateClient: " + clientInfo.getHost() + " " + clientInfo.isDeleted());
if (serverInfo.updateClient(clientInfo)) {
update();
}
}
public void updateServer(final ServerInfo serverInfo) {
if (serverInfo != null) {
ClientInfoAdapter.this.serverInfo = serverInfo;
update();
}
}
public void update() {
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
clear();
for (ClientInfo clientInfo : ClientInfoAdapter.this.serverInfo.getClientInfos()) {
if ((clientInfo != null) && (!hideOffline || clientInfo.isConnected()))
if ((clientInfo != null) && (!hideOffline || clientInfo.isConnected()) && !clientInfo.isDeleted())
add(clientInfo);
}
notifyDataSetChanged();
@ -478,7 +506,7 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
if (this.hideOffline == hideOffline)
return;
this.hideOffline = hideOffline;
update(null);
update();
}
}
}

View file

@ -15,7 +15,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.File;
@ -32,6 +31,8 @@ public class SnapclientService extends Service {
public static final String EXTRA_HOST = "EXTRA_HOST";
public static final String EXTRA_PORT = "EXTRA_PORT";
public static final String ACTION_START = "ACTION_START";
public static final String ACTION_STOP = "ACTION_STOP";
private final IBinder mBinder = new LocalBinder();
private java.lang.Process process = null;
private PowerManager.WakeLock wakeLock = null;
@ -50,57 +51,57 @@ public class SnapclientService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction() == "ACTION_STOP") {
if (intent == null)
return START_NOT_STICKY;
if (intent.getAction() == ACTION_STOP) {
stopService();
return START_NOT_STICKY;
}
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
} else if (intent.getAction() == ACTION_START) {
Intent stopIntent = new Intent(this, SnapclientService.class);
stopIntent.setAction(ACTION_STOP);
PendingIntent piStop = PendingIntent.getService(this, 0, stopIntent, 0);
Intent stopIntent = new Intent(this, SnapclientService.class);
stopIntent.setAction("ACTION_STOP");
PendingIntent piStop = PendingIntent.getService(this, 0, stopIntent, 0);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_media_play)
.setTicker(getText(R.string.ticker_text))
.setContentTitle(getText(R.string.notification_title))
.setContentText(getText(R.string.notification_text))
.setContentInfo(getText(R.string.notification_info))
.setStyle(new NotificationCompat.BigTextStyle().bigText(getText(R.string.notification_text)))
.addAction(R.drawable.ic_media_stop, getString(R.string.stop), piStop);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_media_play)
.setTicker(getText(R.string.ticker_text))
.setContentTitle(getText(R.string.notification_title))
.setContentText(getText(R.string.notification_text))
.setContentInfo(getText(R.string.notification_info))
.setStyle(new NotificationCompat.BigTextStyle().bigText(getText(R.string.notification_text)))
.addAction(R.drawable.ic_media_stop, getString(R.string.stop), piStop);
Intent resultIntent = new Intent(this, MainActivity.class);
Intent resultIntent = new Intent(this, MainActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
builder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
final Notification notification = builder.build();
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
builder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
final Notification notification = builder.build();
// mNotificationManager.notify(123, notification);
startForeground(123, notification);
startForeground(123, notification);
String host = intent.getStringExtra(EXTRA_HOST);
int port = intent.getIntExtra(EXTRA_PORT, 1704);
start(host, port);
// If we get killed, after returning from here, restart
return START_STICKY;
String host = intent.getStringExtra(EXTRA_HOST);
int port = intent.getIntExtra(EXTRA_PORT, 1704);
start(host, port);
return START_STICKY;
}
return START_NOT_STICKY;
}
@Override

View file

@ -29,6 +29,7 @@ public class ClientInfo implements JsonSerialisable {
private Time_t lastSeen;
private boolean connected;
private int latency = 0;
private boolean deleted = false;
public ClientInfo(JSONObject json) {
fromJson(json);
@ -114,6 +115,12 @@ public class ClientInfo implements JsonSerialisable {
return name;
}
public String getVisibleName() {
if ((name != null) && !name.isEmpty())
return name;
return getHost();
}
public void setName(String name) {
this.name = name;
}
@ -134,6 +141,14 @@ public class ClientInfo implements JsonSerialisable {
this.connected = connected;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
@Override
public String toString() {
return "ClientInfo{" +
@ -157,6 +172,7 @@ public class ClientInfo implements JsonSerialisable {
ClientInfo that = (ClientInfo) o;
if (connected != that.connected) return false;
if (deleted != that.deleted) return false;
if (latency != that.latency) return false;
if (mac != null ? !mac.equals(that.mac) : that.mac != null) return false;
if (ip != null ? !ip.equals(that.ip) : that.ip != null) return false;
@ -176,6 +192,7 @@ public class ClientInfo implements JsonSerialisable {
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (volume != null ? volume.hashCode() : 0);
result = 31 * result + (connected ? 1 : 0);
result = 31 * result + (deleted ? 1 : 0);
result = 31 * result + latency;
return result;
}

View file

@ -76,7 +76,7 @@ public class RemoteControl implements TcpClient.TcpClientListener {
JSONArray clients = json.getJSONObject("result").getJSONArray("clients");
for (int i = 0; i < clients.length(); i++) {
final ClientInfo clientInfo = new ClientInfo(clients.getJSONObject(i));
serverInfo.addClient(clientInfo);
serverInfo.updateClient(clientInfo);
}
if (listener != null)
listener.onServerInfo(this, serverInfo);

View file

@ -26,7 +26,7 @@ public class ServerInfo {
return false;
}
public boolean addClient(ClientInfo client) {
public boolean updateClient(ClientInfo client) {
if (client == null)
return false;

View file

@ -1,12 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/myCoordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="de.badaix.snapcast.MainActivity">
<LinearLayout
@ -14,7 +12,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true">
android:layout_centerHorizontal="true"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
@ -48,4 +50,5 @@
</LinearLayout>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>

View file

@ -26,5 +26,7 @@
<string name="client_latency">Latency</string>
<string name="online">online</string>
<string name="action_play_stop">Play/Stop</string>
<string name="client_deleted">Client %1$s deleted</string>
<string name="undo_string">undo</string>
</resources>