client list is a fragment

This commit is contained in:
badaix 2016-01-31 13:17:35 +01:00
parent 0c87becca0
commit 36360476ac
9 changed files with 507 additions and 208 deletions

View file

@ -15,7 +15,8 @@
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleInstance">
android:launchMode="singleInstance"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View file

@ -0,0 +1,206 @@
package de.badaix.snapcast;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import de.badaix.snapcast.control.ClientInfo;
import de.badaix.snapcast.control.ServerInfo;
/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link ClientListFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {@link ClientListFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class ClientListFragment extends Fragment {
private static final String TAG = "ClientList";
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
private ClientInfoItem.ClientInfoItemListener clientInfoItemListener;
private ClientInfoAdapter clientInfoAdapter;
private ServerInfo serverInfo = null;
private boolean hideOffline = false;
public ClientListFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment ClientListFragment.
*/
// TODO: Rename and change types and number of parameters
public static ClientListFragment newInstance(String param1, String param2) {
ClientListFragment fragment = new ClientListFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_client_list, container, false);
ListView lvClient = (ListView) view.findViewById(R.id.lvClient);
clientInfoAdapter = new ClientInfoAdapter(getContext(), clientInfoItemListener);
clientInfoAdapter.setHideOffline(hideOffline);
clientInfoAdapter.updateServer(serverInfo);
lvClient.setAdapter(clientInfoAdapter);
return view;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
clientInfoItemListener = (ClientInfoItem.ClientInfoItemListener) context;
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public void updateServer(ServerInfo serverInfo) {
this.serverInfo = serverInfo;
if (clientInfoAdapter != null)
clientInfoAdapter.updateServer(this.serverInfo);
}
public void setHideOffline(boolean hide) {
this.hideOffline = hide;
if (clientInfoAdapter != null)
clientInfoAdapter.setHideOffline(hideOffline);
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
public class ClientInfoAdapter extends ArrayAdapter<ClientInfo> {
private Context context;
private ClientInfoItem.ClientInfoItemListener listener;
private boolean hideOffline = false;
private ServerInfo serverInfo = new ServerInfo();
public ClientInfoAdapter(Context context, ClientInfoItem.ClientInfoItemListener listener) {
super(context, 0);
this.context = context;
this.listener = listener;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ClientInfo clientInfo = getItem(position);
final ClientInfoItem clientInfoItem;
if (convertView != null) {
clientInfoItem = (ClientInfoItem) convertView;
clientInfoItem.setClientInfo(clientInfo);
} else {
clientInfoItem = new ClientInfoItem(context, clientInfo);
}
clientInfoItem.setListener(listener);
return clientInfoItem;
}
public void updateServer(final ServerInfo serverInfo) {
if (serverInfo != null) {
ClientInfoAdapter.this.serverInfo = serverInfo;
update();
}
}
public void update() {
ClientListFragment.this.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
clear();
for (ClientInfo clientInfo : ClientInfoAdapter.this.serverInfo.getClientInfos()) {
if ((clientInfo != null) && (!hideOffline || clientInfo.isConnected()) && !clientInfo.isDeleted())
add(clientInfo);
}
notifyDataSetChanged();
}
});
}
public boolean isHideOffline() {
return hideOffline;
}
public void setHideOffline(boolean hideOffline) {
if (this.hideOffline == hideOffline)
return;
this.hideOffline = hideOffline;
update();
}
}
}

View file

@ -10,22 +10,23 @@ import android.net.Uri;
import android.net.nsd.NsdServiceInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.design.widget.Snackbar;
import android.support.design.widget.Snackbar.Callback;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.TextView;
import com.google.android.gms.appindexing.Action;
@ -38,18 +39,24 @@ import de.badaix.snapcast.control.ServerInfo;
import de.badaix.snapcast.utils.NsdHelper;
import de.badaix.snapcast.utils.Setup;
public class MainActivity extends AppCompatActivity implements ClientInfoItem.ClientInfoItemListener, RemoteControl.RemoteControlListener, SnapclientService.SnapclientListener, NsdHelper.NsdHelperListener {
public class MainActivity extends AppCompatActivity implements ClientListFragment.OnFragmentInteractionListener, ClientInfoItem.ClientInfoItemListener, RemoteControl.RemoteControlListener, SnapclientService.SnapclientListener, NsdHelper.NsdHelperListener {
private static final String TAG = "Main";
private static final String SERVICE_NAME = "Snapcast";
boolean bound = false;
private MenuItem miStartStop = null;
private String host = "";
private int port = 1704;
private RemoteControl remoteControl = null;
private ClientInfoAdapter clientInfoAdapter;
private ServerInfo serverInfo = null;
private SnapclientService snapclientService;
private Runnable enablePlayButtonRunnable;
private Handler handler;
private SectionsPagerAdapter sectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
private ViewPager mViewPager;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
@ -102,9 +109,19 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
tvInfo.setText("Sample rate: " + rate + ", buffer size: " + size);
}
clientInfoAdapter = new ClientInfoAdapter(this, this);
ListView lvClient = (ListView) findViewById(R.id.lvClient);
lvClient.setAdapter(clientInfoAdapter);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
sectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
getSupportActionBar().setSubtitle("Host: no Snapserver found");
new Thread(new Runnable() {
@ -119,16 +136,6 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
handler = new Handler();
enablePlayButtonRunnable =
new Runnable() {
@Override
public void run() {
if (miStartStop != null)
miStartStop.setEnabled(true);
}
};
}
@Override
@ -141,7 +148,7 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
boolean isChecked = settings.getBoolean("hide_offline", false);
MenuItem menuItem = menu.findItem(R.id.action_hide_offline);
menuItem.setChecked(isChecked);
clientInfoAdapter.setHideOffline(isChecked);
sectionsPagerAdapter.setHideOffline(isChecked);
return true;
}
@ -155,15 +162,14 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
//noinspection SimplifiableIfStatement
if (id == R.id.action_scan) {
// NsdHelper.getInstance(this).startListening("*._tcp.", "SnapCast", this);
NsdHelper.getInstance(this).startListening("_snapcast._tcp.", "Snapcast", this);
NsdHelper.getInstance(this).startListening("_snapcast._tcp.", SERVICE_NAME, this);
return true;
} else if (id == R.id.action_play_stop) {
if (bound && snapclientService.isRunning()) {
stopSnapclient();
} else {
startSnapclient();
item.setEnabled(false);
handler.postDelayed(enablePlayButtonRunnable, 5000);
startSnapclient();
}
return true;
} else if (id == R.id.action_hide_offline) {
@ -172,11 +178,11 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("hide_offline", item.isChecked());
editor.apply();
clientInfoAdapter.setHideOffline(item.isChecked());
sectionsPagerAdapter.setHideOffline(item.isChecked());
return true;
} else if (id == R.id.action_refresh) {
if ((remoteControl != null) && remoteControl.isConnected())
remoteControl.getServerStatus();
startRemoteControl();
remoteControl.getServerStatus();
} else if (id == R.id.action_about) {
Intent intent = new Intent(this, AboutActivity.class);
startActivity(intent);
@ -186,17 +192,22 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
}
private void updateStartStopMenuItem() {
if (bound && snapclientService.isRunning()) {
Log.d(TAG, "updateStartStopMenuItem: ic_media_stop");
miStartStop.setIcon(R.drawable.ic_media_stop);
} else {
Log.d(TAG, "updateStartStopMenuItem: ic_media_play");
miStartStop.setIcon(R.drawable.ic_media_play);
}
if (miStartStop != null) {
handler.removeCallbacks(enablePlayButtonRunnable);
miStartStop.setEnabled(true);
}
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
if (bound && snapclientService.isRunning()) {
Log.d(TAG, "updateStartStopMenuItem: ic_media_stop");
miStartStop.setIcon(R.drawable.ic_media_stop);
} else {
Log.d(TAG, "updateStartStopMenuItem: ic_media_play");
miStartStop.setIcon(R.drawable.ic_media_play);
}
if (miStartStop != null) {
miStartStop.setEnabled(true);
}
}
});
}
private void startSnapclient() {
@ -241,7 +252,7 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
public void onStart() {
super.onStart();
NsdHelper.getInstance(this).startListening("_snapcast._tcp.", "Snapcast", this);
NsdHelper.getInstance(this).startListening("_snapcast._tcp.", SERVICE_NAME, this);
Intent intent = new Intent(this, SnapclientService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
@ -296,67 +307,27 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
}
@Override
public void onPlayerStart() {
public void onPlayerStart(SnapclientService snapclientService) {
Log.d(TAG, "onPlayerStart");
updateStartStopMenuItem();
}
@Override
public void onPlayerStop() {
public void onPlayerStop(SnapclientService snapclientService) {
Log.d(TAG, "onPlayerStop");
updateStartStopMenuItem();
}
@Override
public void onLog(String log) {
public void onLog(SnapclientService snapclientService, String log) {
Log.d(TAG, log);
}
@Override
public void onVolumeChanged(ClientInfoItem clientInfoItem, int percent) {
remoteControl.setVolume(clientInfoItem.getClientInfo(), percent);
public void onError(SnapclientService snapclientService, String msg, Exception exception) {
updateStartStopMenuItem();
}
@Override
public void onMute(ClientInfoItem clientInfoItem, boolean mute) {
remoteControl.setMute(clientInfoItem.getClientInfo(), mute);
}
@Override
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
public void onPropertiesClicked(ClientInfoItem clientInfoItem) {
Intent intent = new Intent(this, ClientSettingsActivity.class);
intent.putExtra("clientInfo", clientInfoItem.getClientInfo());
startActivityForResult(intent, 1);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
@ -368,7 +339,7 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
if (requestCode == 1) {
ClientInfo clientInfo = data.getParcelableExtra("clientInfo");
remoteControl.setName(clientInfo, clientInfo.getName());
clientInfoAdapter.updateClient(clientInfo);
//TODO clientInfoAdapter.updateClient(clientInfo);
}
}
@ -386,15 +357,16 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
public void onClientEvent(RemoteControl remoteControl, ClientInfo clientInfo, RemoteControl.ClientEvent event) {
Log.d(TAG, "onClientEvent: " + event.toString());
if (event == RemoteControl.ClientEvent.deleted)
clientInfoAdapter.removeClient(clientInfo);
serverInfo.removeClient(clientInfo);
else
clientInfoAdapter.updateClient(clientInfo);
serverInfo.updateClient(clientInfo);
sectionsPagerAdapter.updateServer(serverInfo);
}
@Override
public void onServerInfo(RemoteControl remoteControl, ServerInfo serverInfo) {
clientInfoAdapter.updateServer(serverInfo);
this.serverInfo = serverInfo;
sectionsPagerAdapter.updateServer(serverInfo);
}
private void setActionbarSubtitle(final String subtitle) {
@ -418,81 +390,112 @@ public class MainActivity extends AppCompatActivity implements ClientInfoItem.Cl
NsdHelper.getInstance(this).stopListening();
}
private class ClientInfoAdapter extends ArrayAdapter<ClientInfo> {
private Context context;
private ClientInfoItem.ClientInfoItemListener listener;
private boolean hideOffline = false;
private ServerInfo serverInfo = new ServerInfo();
public ClientInfoAdapter(Context context, ClientInfoItem.ClientInfoItemListener listener) {
super(context, 0);
this.context = context;
this.listener = listener;
}
@Override
public void onFragmentInteraction(Uri uri) {
Log.d(TAG, "onFragmentInteraction: " + uri);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ClientInfo clientInfo = getItem(position);
final ClientInfoItem clientInfoItem;
@Override
public void onVolumeChanged(ClientInfoItem clientInfoItem, int percent) {
remoteControl.setVolume(clientInfoItem.getClientInfo(), percent);
}
if (convertView != null) {
clientInfoItem = (ClientInfoItem) convertView;
clientInfoItem.setClientInfo(clientInfo);
} else {
clientInfoItem = new ClientInfoItem(context, clientInfo);
@Override
public void onMute(ClientInfoItem clientInfoItem, boolean mute) {
remoteControl.setMute(clientInfoItem.getClientInfo(), mute);
}
@Override
public void onDeleteClicked(final ClientInfoItem clientInfoItem) {
final ClientInfo clientInfo = clientInfoItem.getClientInfo();
clientInfo.setDeleted(true);
serverInfo.updateClient(clientInfo);
// sectionsPagerAdapter.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);
serverInfo.updateClient(clientInfo);
// sectionsPagerAdapter.update();
}
clientInfoItem.setListener(listener);
return clientInfoItem;
}
public void removeClient(final ClientInfo clientInfo) {
if ((clientInfo != null) && serverInfo.removeClient(clientInfo)) {
Log.d(TAG, "removeClient 1: " + clientInfo.getMac());
update();
});
mySnackbar.setCallback(new Snackbar.Callback() {
@Override
public void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
if (event != DISMISS_EVENT_ACTION) {
remoteControl.delete(clientInfo);
serverInfo.removeClient(clientInfo);
}
}
}
});
mySnackbar.show();
}
public void updateClient(final ClientInfo clientInfo) {
Log.d(TAG, "updateClient: " + clientInfo.getHost() + " " + clientInfo.isDeleted());
if (serverInfo.updateClient(clientInfo)) {
update();
}
@Override
public void onPropertiesClicked(ClientInfoItem clientInfoItem) {
Intent intent = new Intent(this, ClientSettingsActivity.class);
intent.putExtra("clientInfo", clientInfoItem.getClientInfo());
startActivityForResult(intent, 1);
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private ClientListFragment clientListFragment;
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
clientListFragment = ClientListFragment.newInstance("TODO1", "TODO2");
}
public void updateServer(final ServerInfo serverInfo) {
if (serverInfo != null) {
ClientInfoAdapter.this.serverInfo = serverInfo;
update();
clientListFragment.updateServer(serverInfo);
}
public void setHideOffline(boolean hide) {
clientListFragment.setHideOffline(hide);
}
// public void update() {
// clientListFragment.update();
// }
@Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return clientListFragment;
}
@Override
public int getCount() {
// Show 3 total pages.
return 1;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "SECTION 1";
case 1:
return "SECTION 2";
case 2:
return "SECTION 3";
}
return null;
}
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()) && !clientInfo.isDeleted())
add(clientInfo);
}
notifyDataSetChanged();
}
});
}
public boolean isHideOffline() {
return hideOffline;
}
public void setHideOffline(boolean hideOffline) {
if (this.hideOffline == hideOffline)
return;
this.hideOffline = hideOffline;
update();
}
}
}

View file

@ -29,6 +29,15 @@ import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
public class SnapclientService extends Service {
public interface SnapclientListener {
void onPlayerStart(SnapclientService snapclientService);
void onPlayerStop(SnapclientService snapclientService);
void onLog(SnapclientService snapclientService, String log);
void onError(SnapclientService snapclientService, String msg, Exception exception);
}
public static final String EXTRA_HOST = "EXTRA_HOST";
public static final String EXTRA_PORT = "EXTRA_PORT";
public static final String ACTION_START = "ACTION_START";
@ -40,6 +49,7 @@ public class SnapclientService extends Service {
private Thread reader = null;
private boolean running = false;
private SnapclientListener listener = null;
private boolean logReceived;
public boolean isRunning() {
return running;
@ -156,44 +166,60 @@ public class SnapclientService extends Service {
String line;
try {
while ((line = bufferedReader.readLine()) != null) {
if (listener != null)
listener.onLog(line);
log(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
logReceived = false;
reader.start();
running = true;
if (listener != null)
listener.onPlayerStart();
} catch (IOException e) {
//TODO: wait for started message on stdout
/* long now = System.currentTimeMillis();
while (!logReceived) {
if (System.currentTimeMillis() > now + 1000)
throw new Exception("start timeout");
Thread.sleep(100, 0);
}
*/
} catch (Exception e) {
e.printStackTrace();
if (listener != null)
listener.onError(this, e.getMessage(), e);
stop();
}
}
private void stop() {
if (reader != null)
reader.interrupt();
if (process != null)
process.destroy();
if ((wakeLock != null) && wakeLock.isHeld())
wakeLock.release();
if ((wifiWakeLock != null) && wifiWakeLock.isHeld())
wifiWakeLock.release();
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_DEFAULT);
running = false;
private void log(String msg) {
if (!logReceived) {
logReceived = true;
running = true;
if (listener != null)
listener.onPlayerStart(this);
}
if (listener != null)
listener.onPlayerStop();
listener.onLog(SnapclientService.this, msg);
}
public interface SnapclientListener {
void onPlayerStart();
void onPlayerStop();
void onLog(String log);
private void stop() {
try {
if (reader != null)
reader.interrupt();
if (process != null)
process.destroy();
if ((wakeLock != null) && wakeLock.isHeld())
wakeLock.release();
if ((wifiWakeLock != null) && wifiWakeLock.isHeld())
wifiWakeLock.release();
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_DEFAULT);
running = false;
} catch (Exception e) {
e.printStackTrace();
}
if (listener != null)
listener.onPlayerStop(this);
}
/**

View file

@ -1,11 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<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"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="de.badaix.snapcast.MainActivity">
android:fitsSystemWindows="true"
tools:context="de.badaix.swipe.MainActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<!-- android:paddingTop="@dimen/appbar_padding_top" -->
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay">
<!-- app:layout_scrollFlags="scroll|enterAlways" -->
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<LinearLayout
android:orientation="vertical"
@ -39,15 +71,6 @@
android:visibility="gone"
android:id="@+id/button" />
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:listSelector="@android:color/transparent"
android:cacheColorHint="@android:color/transparent"
android:divider="@null"
android:dividerHeight="1dp"
android:id="@+id/lvClient" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>

View file

@ -0,0 +1,17 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="de.badaix.snapcast.ClientListFragment">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:listSelector="@android:color/transparent"
android:cacheColorHint="@android:color/transparent"
android:divider="@null"
android:dividerHeight="1dp"
android:id="@+id/lvClient" />
</FrameLayout>

View file

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="second_grey">#ff999999</color>
<color name="card_white">#ffffffff</color>
<color name="card_shadow">#8c666666</color>

View file

@ -32,5 +32,8 @@
<string name="title_activity_about">About</string>
<string name="about_file">about.html</string>
<string name="about">About</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
</resources>

View file

@ -1,26 +1,12 @@
<resources>
<color name="color_background">#EEEEEE</color>
<color name="actionbar_background">#37474F</color>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowBackground">@color/color_background</item>
<item name="android:actionBarStyle">@style/MyActionBar</item>
<!-- Support library compatibility -->
<item name="actionBarStyle">@style/MyActionBar</item>
<!-- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> -->
<!-- Customize your theme here. -->
</style>
<style name="MyActionBar" parent="@style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="android:background">@color/actionbar_background</item>
<!-- Support library compatibility -->
<item name="background">@color/actionbar_background</item>
</style>
<style name="PlayerButton" parent="android:Widget.Holo.ImageButton">
<item name="android:background">?android:attr/actionBarItemBackground</item>
<!-- <item name="android:minHeight">@dimen/playerbutton_height</item> -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
@ -28,8 +14,39 @@
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
<!-- Base application theme.
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowBackground">@color/color_background</item>
<item name="android:actionBarStyle">@style/MyActionBar</item>
<!- Support library compatibility
<item name="actionBarStyle">@style/MyActionBar</item>
<!- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!- Customize your theme here.
</style>
<style name="MyActionBar" parent="@style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="android:background">@color/actionbar_background</item>
<!- Support library compatibility -
<item name="background">@color/actionbar_background</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<style name="PlayerButton" parent="android:Widget.Holo.ImageButton">
<item name="android:background">?android:attr/actionBarItemBackground</item>
<!- <item name="android:minHeight">@dimen/playerbutton_height</item> -
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
-->
</resources>