mirror of
https://github.com/badaix/snapcast.git
synced 2025-08-06 10:09:33 +02:00
Sonos like group volume control
This commit is contained in:
parent
fdb292edb4
commit
9f11bd13e7
3 changed files with 97 additions and 40 deletions
|
@ -62,7 +62,7 @@ public class ClientItem extends LinearLayout implements SeekBar.OnSeekBarChangeL
|
||||||
setClient(client);
|
setClient(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update() {
|
public void update() {
|
||||||
//Log.d(TAG, "update: " + client.getVisibleName() + ", connected: " + client.isConnected());
|
//Log.d(TAG, "update: " + client.getVisibleName() + ", connected: " + client.isConnected());
|
||||||
title.setText(client.getVisibleName());
|
title.setText(client.getVisibleName());
|
||||||
title.setEnabled(client.isConnected());
|
title.setEnabled(client.isConnected());
|
||||||
|
|
|
@ -19,13 +19,18 @@
|
||||||
package de.badaix.snapcast;
|
package de.badaix.snapcast;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
import de.badaix.snapcast.control.json.Client;
|
import de.badaix.snapcast.control.json.Client;
|
||||||
import de.badaix.snapcast.control.json.Group;
|
import de.badaix.snapcast.control.json.Group;
|
||||||
import de.badaix.snapcast.control.json.ServerStatus;
|
import de.badaix.snapcast.control.json.ServerStatus;
|
||||||
|
@ -36,7 +41,7 @@ import de.badaix.snapcast.control.json.Stream;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
public class GroupItem extends LinearLayout implements SeekBar.OnSeekBarChangeListener, View.OnClickListener, ClientItem.ClientItemListener {
|
public class GroupItem extends LinearLayout implements SeekBar.OnSeekBarChangeListener, View.OnClickListener, ClientItem.ClientItemListener, View.OnTouchListener {
|
||||||
|
|
||||||
private static final String TAG = "GroupItem";
|
private static final String TAG = "GroupItem";
|
||||||
|
|
||||||
|
@ -47,10 +52,13 @@ public class GroupItem extends LinearLayout implements SeekBar.OnSeekBarChangeLi
|
||||||
private LinearLayout llClient;
|
private LinearLayout llClient;
|
||||||
private Group group;
|
private Group group;
|
||||||
private ServerStatus server;
|
private ServerStatus server;
|
||||||
private TextView tvStreamState = null;
|
private TextView tvStreamName = null;
|
||||||
private GroupItemListener listener = null;
|
private GroupItemListener listener = null;
|
||||||
private LinearLayout llVolume;
|
private LinearLayout llVolume;
|
||||||
private boolean hideOffline = false;
|
private boolean hideOffline = false;
|
||||||
|
private Vector<ClientItem> clientItems = null;
|
||||||
|
private Vector<Integer> clientVolumes = null;
|
||||||
|
private int groupVolume = 0;
|
||||||
|
|
||||||
public GroupItem(Context context, ServerStatus server, Group group) {
|
public GroupItem(Context context, ServerStatus server, Group group) {
|
||||||
super(context);
|
super(context);
|
||||||
|
@ -68,28 +76,39 @@ public class GroupItem extends LinearLayout implements SeekBar.OnSeekBarChangeLi
|
||||||
llVolume.setVisibility(GONE);
|
llVolume.setVisibility(GONE);
|
||||||
llClient = (LinearLayout) findViewById(R.id.llClient);
|
llClient = (LinearLayout) findViewById(R.id.llClient);
|
||||||
llClient.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
|
llClient.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
|
||||||
tvStreamState = (TextView) findViewById(R.id.tvStreamState);
|
tvStreamName = (TextView) findViewById(R.id.tvStreamName);
|
||||||
volumeSeekBar.setOnSeekBarChangeListener(this);
|
volumeSeekBar.setOnSeekBarChangeListener(this);
|
||||||
|
volumeSeekBar.setOnTouchListener(this);
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
clientItems = new Vector<>();
|
||||||
|
clientVolumes = new Vector<>();
|
||||||
setGroup(group);
|
setGroup(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update() {
|
private void update() {
|
||||||
// title.setText(group.getName());
|
// title.setText(group.getName());
|
||||||
llClient.removeAllViews();
|
llClient.removeAllViews();
|
||||||
|
clientItems.clear();
|
||||||
for (Client client : group.getClients()) {
|
for (Client client : group.getClients()) {
|
||||||
if ((client == null) || client.isDeleted() || (hideOffline && !client.isConnected()))
|
if ((client == null) || client.isDeleted() || (hideOffline && !client.isConnected()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ClientItem clientItem = new ClientItem(this.getContext(), server, client);
|
ClientItem clientItem = new ClientItem(this.getContext(), server, client);
|
||||||
clientItem.setListener(this);
|
clientItem.setListener(this);
|
||||||
|
clientItems.add(clientItem);
|
||||||
llClient.addView(clientItem);
|
llClient.addView(clientItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clientItems.size() >= 2)
|
||||||
|
llVolume.setVisibility(VISIBLE);
|
||||||
|
else
|
||||||
|
llVolume.setVisibility(GONE);
|
||||||
|
updateVolume();
|
||||||
|
|
||||||
Stream stream = server.getStream(group.getStreamId());
|
Stream stream = server.getStream(group.getStreamId());
|
||||||
if ((tvStreamState == null) || (stream == null))
|
if ((tvStreamName == null) || (stream == null))
|
||||||
return;
|
return;
|
||||||
tvStreamState.setText(stream.getName());
|
tvStreamName.setText(stream.getName());
|
||||||
/* String codec = stream.getUri().getQuery().get("codec");
|
/* String codec = stream.getUri().getQuery().get("codec");
|
||||||
if (codec.contains(":"))
|
if (codec.contains(":"))
|
||||||
codec = codec.split(":")[0];
|
codec = codec.split(":")[0];
|
||||||
|
@ -104,6 +123,15 @@ public class GroupItem extends LinearLayout implements SeekBar.OnSeekBarChangeLi
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateVolume() {
|
||||||
|
double meanVolume = 0;
|
||||||
|
for (ClientItem c : clientItems) {
|
||||||
|
meanVolume += c.getClient().getConfig().getVolume().getPercent();
|
||||||
|
}
|
||||||
|
meanVolume /= clientItems.size();
|
||||||
|
volumeSeekBar.setProgress((int) (Math.ceil(meanVolume)));
|
||||||
|
}
|
||||||
|
|
||||||
public Group getGroup() {
|
public Group getGroup() {
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
@ -126,14 +154,46 @@ public class GroupItem extends LinearLayout implements SeekBar.OnSeekBarChangeLi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||||
/* if (fromUser && (listener != null)) {
|
if (!fromUser)
|
||||||
Volume volume = new Volume(progress, false);
|
return;
|
||||||
client.setVolume(volume);
|
|
||||||
listener.onVolumeChanged(this, volume.getPercent());
|
int delta = progress - groupVolume;
|
||||||
|
if (delta == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double ratio;
|
||||||
|
if (delta < 0)
|
||||||
|
ratio = (double) (groupVolume - progress) / (double) groupVolume;
|
||||||
|
else
|
||||||
|
ratio = (double) (progress - groupVolume) / (double) (100 - groupVolume);
|
||||||
|
|
||||||
|
for (int i = 0; i < clientItems.size(); ++i) {
|
||||||
|
ClientItem clientItem = clientItems.get(i);
|
||||||
|
int clientVolume = clientVolumes.get(i);
|
||||||
|
int newVolume = clientVolume;
|
||||||
|
if (delta < 0)
|
||||||
|
newVolume -= ratio * clientVolume;
|
||||||
|
else
|
||||||
|
newVolume += ratio * (100 - clientVolume);
|
||||||
|
clientItem.getClient().getConfig().getVolume().setPercent(newVolume);
|
||||||
|
clientItem.update();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
|
clientVolumes.clear();
|
||||||
|
for (int i = 0; i < clientItems.size(); ++i)
|
||||||
|
clientVolumes.add(clientItems.get(i).getClient().getConfig().getVolume().getPercent());
|
||||||
|
groupVolume = volumeSeekBar.getProgress();
|
||||||
|
Log.d(TAG, "onTouch: " + groupVolume);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
/* TODO: group if (v == ibMute) {
|
/* TODO: group if (v == ibMute) {
|
||||||
|
@ -162,6 +222,7 @@ public class GroupItem extends LinearLayout implements SeekBar.OnSeekBarChangeLi
|
||||||
public void onVolumeChanged(ClientItem clientItem, int percent, boolean mute) {
|
public void onVolumeChanged(ClientItem clientItem, int percent, boolean mute) {
|
||||||
if (listener != null)
|
if (listener != null)
|
||||||
listener.onVolumeChanged(this, clientItem, percent, mute);
|
listener.onVolumeChanged(this, clientItem, percent, mute);
|
||||||
|
updateVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
<!-- android:descendantFocusability="afterDescendants"-->
|
<!-- android:descendantFocusability="afterDescendants"-->
|
||||||
<!-- android:paddingRight="?android:attr/scrollbarSize"-->
|
<!-- android:paddingRight="?android:attr/scrollbarSize"-->
|
||||||
<!-- android:background="@drawable/big_card"-->
|
<!-- android:background="@drawable/big_card"-->
|
||||||
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
<android.support.v7.widget.CardView android:id="@+id/card_view"
|
||||||
android:id="@+id/card_view"
|
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
card_view:cardCornerRadius="4dp"
|
card_view:cardCornerRadius="4dp"
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
android:src="@drawable/ic_settings_black_24dp"/>
|
android:src="@drawable/ic_settings_black_24dp"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvStreamState"
|
android:id="@+id/tvStreamName"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:text="Stream state"
|
android:text="Stream name"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
@ -79,42 +79,36 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"/>
|
android:orientation="vertical"/>
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/llVolume"
|
android:id="@+id/llVolume"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_toLeftOf="@id/ibOverflow"
|
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="1dip"
|
||||||
|
android:layout_marginLeft="5dip"
|
||||||
|
android:layout_marginRight="5dip"
|
||||||
|
android:layout_marginBottom="5dip"
|
||||||
|
android:layout_marginTop="5dip"
|
||||||
|
android:alpha="0.1"
|
||||||
|
android:background="#000000"/>
|
||||||
|
|
||||||
<!--
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="marquee"
|
|
||||||
android:fadingEdge="horizontal"
|
|
||||||
android:paddingBottom="1dp"
|
|
||||||
android:paddingLeft="5dp"
|
|
||||||
android:paddingTop="2dp"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:text="Title"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:paddingBottom="5dp"
|
||||||
android:paddingBottom="4dp"
|
android:paddingLeft="3dp"
|
||||||
android:paddingLeft="3dp">
|
android:paddingRight="3dp"
|
||||||
|
android:paddingTop="3dp">
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/ibMute"
|
android:id="@+id/ibMute"
|
||||||
android:layout_width="60dp"
|
android:layout_width="60dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
android:background="@null"
|
android:background="@null"
|
||||||
android:src="@drawable/ic_speaker_icon"/>
|
android:src="@drawable/ic_speaker_icon"/>
|
||||||
|
|
||||||
|
@ -122,9 +116,11 @@
|
||||||
android:id="@+id/volumeSeekBar"
|
android:id="@+id/volumeSeekBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toLeftOf="@+id/ibSettings"
|
||||||
|
android:layout_toRightOf="@+id/ibMute"
|
||||||
android:max="100"/>
|
android:max="100"/>
|
||||||
</LinearLayout>
|
</RelativeLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</android.support.v7.widget.CardView>
|
</android.support.v7.widget.CardView>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue