Implemented VolumeLevelIndicator widget (#406)
* Refactored NowPlayingFragment to use new widget * Refactored UIUtils.highlightImageView to reduce code duplication
This commit is contained in:
parent
3be2d74f0a
commit
85bcd846f2
|
@ -464,7 +464,7 @@ abstract public class AbstractInfoFragment extends AbstractFragment
|
||||||
if (checkStoragePermission()) {
|
if (checkStoragePermission()) {
|
||||||
if (Settings.allowedDownloadNetworkTypes(getActivity()) != 0) {
|
if (Settings.allowedDownloadNetworkTypes(getActivity()) != 0) {
|
||||||
listener.onClick(view);
|
listener.onClick(view);
|
||||||
setButtonState(downloadButton, true);
|
UIUtils.highlightImageView(getActivity(), downloadButton, true);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(getActivity(), R.string.no_connection_type_selected, Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.no_connection_type_selected, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
@ -500,7 +500,7 @@ abstract public class AbstractInfoFragment extends AbstractFragment
|
||||||
* @param state true if item has been watched/listened too, false otherwise
|
* @param state true if item has been watched/listened too, false otherwise
|
||||||
*/
|
*/
|
||||||
protected void setDownloadButtonState(boolean state) {
|
protected void setDownloadButtonState(boolean state) {
|
||||||
setButtonState(downloadButton, state);
|
UIUtils.highlightImageView(getActivity(), downloadButton, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -515,16 +515,8 @@ abstract public class AbstractInfoFragment extends AbstractFragment
|
||||||
setToggleButtonState(pinUnpinButton, state);
|
setToggleButtonState(pinUnpinButton, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setButtonState(ImageButton button, boolean state) {
|
|
||||||
if (state) {
|
|
||||||
UIUtils.highlightImageView(getActivity(), button);
|
|
||||||
} else {
|
|
||||||
button.clearColorFilter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setToggleButtonState(ImageButton button, boolean state) {
|
private void setToggleButtonState(ImageButton button, boolean state) {
|
||||||
setButtonState(button, state);
|
UIUtils.highlightImageView(getActivity(), button, state);
|
||||||
button.setTag(state);
|
button.setTag(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ import android.widget.ImageView;
|
||||||
import android.widget.PopupMenu;
|
import android.widget.PopupMenu;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
import android.widget.SeekBar;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
@ -57,6 +56,7 @@ import org.xbmc.kore.jsonrpc.type.VideoType;
|
||||||
import org.xbmc.kore.ui.generic.GenericSelectDialog;
|
import org.xbmc.kore.ui.generic.GenericSelectDialog;
|
||||||
import org.xbmc.kore.ui.sections.video.AllCastActivity;
|
import org.xbmc.kore.ui.sections.video.AllCastActivity;
|
||||||
import org.xbmc.kore.ui.widgets.MediaProgressIndicator;
|
import org.xbmc.kore.ui.widgets.MediaProgressIndicator;
|
||||||
|
import org.xbmc.kore.ui.widgets.VolumeLevelIndicator;
|
||||||
import org.xbmc.kore.utils.LogUtils;
|
import org.xbmc.kore.utils.LogUtils;
|
||||||
import org.xbmc.kore.utils.UIUtils;
|
import org.xbmc.kore.utils.UIUtils;
|
||||||
import org.xbmc.kore.utils.Utils;
|
import org.xbmc.kore.utils.Utils;
|
||||||
|
@ -153,8 +153,7 @@ public class NowPlayingFragment extends Fragment
|
||||||
@InjectView(R.id.media_undertitle) TextView mediaUndertitle;
|
@InjectView(R.id.media_undertitle) TextView mediaUndertitle;
|
||||||
@InjectView(R.id.progress_info) MediaProgressIndicator mediaProgressIndicator;
|
@InjectView(R.id.progress_info) MediaProgressIndicator mediaProgressIndicator;
|
||||||
|
|
||||||
@InjectView(R.id.volume_bar) SeekBar volumeSeekBar;
|
@InjectView(R.id.volume_level_indicator) VolumeLevelIndicator volumeLevelIndicator;
|
||||||
@InjectView(R.id.volume_text) TextView volumeTextView;
|
|
||||||
|
|
||||||
@InjectView(R.id.media_details) RelativeLayout mediaDetailsPanel;
|
@InjectView(R.id.media_details) RelativeLayout mediaDetailsPanel;
|
||||||
@InjectView(R.id.rating) TextView mediaRating;
|
@InjectView(R.id.rating) TextView mediaRating;
|
||||||
|
@ -202,6 +201,14 @@ public class NowPlayingFragment extends Fragment
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
volumeLevelIndicator.setOnVolumeChangeListener(new VolumeLevelIndicator.OnVolumeChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onVolumeChanged(int volume) {
|
||||||
|
new Application.SetVolume(volume).execute(hostManager.getConnection(),
|
||||||
|
defaultIntActionCallback, new Handler());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// // Pad main content view to overlap with bottom system bar
|
// // Pad main content view to overlap with bottom system bar
|
||||||
// UIUtils.setPaddingForSystemBars(getActivity(), mediaPanel, false, false, true);
|
// UIUtils.setPaddingForSystemBars(getActivity(), mediaPanel, false, false, true);
|
||||||
// mediaPanel.setClipToPadding(false);
|
// mediaPanel.setClipToPadding(false);
|
||||||
|
@ -300,18 +307,10 @@ public class NowPlayingFragment extends Fragment
|
||||||
// the mute state on the host. We do this to make it clear to the user that the button
|
// the mute state on the host. We do this to make it clear to the user that the button
|
||||||
// was pressed.
|
// was pressed.
|
||||||
HostConnectionObserver.HostState hostState = hostConnectionObserver.getHostState();
|
HostConnectionObserver.HostState hostState = hostConnectionObserver.getHostState();
|
||||||
setVolumeState(!hostState.isVolumeMuted(), hostState.getVolumeLevel());
|
UIUtils.highlightImageView(getActivity(), volumeMuteButton, !hostState.isVolumeMuted());
|
||||||
|
|
||||||
Application.SetMute action = new Application.SetMute();
|
Application.SetMute action = new Application.SetMute();
|
||||||
action.execute(hostManager.getConnection(), new ApiCallback<Boolean>() {
|
action.execute(hostManager.getConnection(), defaultBooleanActionCallback, new Handler());
|
||||||
@Override
|
|
||||||
public void onSuccess(Boolean result) {
|
|
||||||
//We depend on the listener to correct the mute button state
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(int errorCode, String description) { }
|
|
||||||
}, callbackHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.shuffle)
|
@OnClick(R.id.shuffle)
|
||||||
|
@ -618,7 +617,8 @@ public class NowPlayingFragment extends Fragment
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applicationOnVolumeChanged(int volume, boolean muted) {
|
public void applicationOnVolumeChanged(int volume, boolean muted) {
|
||||||
setVolumeState(muted, volume);
|
volumeLevelIndicator.setVolume(muted, volume);
|
||||||
|
UIUtils.highlightImageView(getActivity(), volumeMuteButton, muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore this
|
// Ignore this
|
||||||
|
@ -797,8 +797,6 @@ public class NowPlayingFragment extends Fragment
|
||||||
}
|
}
|
||||||
styledAttributes.recycle();
|
styledAttributes.recycle();
|
||||||
|
|
||||||
volumeSeekBar.setOnSeekBarChangeListener(volumeSeekbarChangeListener);
|
|
||||||
|
|
||||||
Resources resources = getActivity().getResources();
|
Resources resources = getActivity().getResources();
|
||||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||||
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||||
|
@ -916,56 +914,4 @@ public class NowPlayingFragment extends Fragment
|
||||||
if (plot == null) return null;
|
if (plot == null) return null;
|
||||||
return plot.replaceAll("\\[.*\\]", "");
|
return plot.replaceAll("\\[.*\\]", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private int mediaTotalTime = 0,
|
|
||||||
mediaCurrentTime = 0; // s
|
|
||||||
private static final int SEEK_BAR_UPDATE_INTERVAL = 1000; // ms
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets UI volume state
|
|
||||||
* @param muted whether volume is muted
|
|
||||||
* @param volume
|
|
||||||
*/
|
|
||||||
private void setVolumeState(Boolean muted, int volume) {
|
|
||||||
if (!isAdded()) return;
|
|
||||||
|
|
||||||
if (muted) {
|
|
||||||
volumeSeekBar.setProgress(0);
|
|
||||||
volumeTextView.setText(R.string.muted);
|
|
||||||
|
|
||||||
Resources.Theme theme = getActivity().getTheme();
|
|
||||||
TypedArray styledAttributes = theme.obtainStyledAttributes(new int[] {
|
|
||||||
R.attr.colorAccent});
|
|
||||||
volumeMuteButton.setColorFilter(
|
|
||||||
styledAttributes.getColor(0,
|
|
||||||
getActivity().getResources().getColor(R.color.accent_default)));
|
|
||||||
styledAttributes.recycle();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
volumeSeekBar.setProgress(volume);
|
|
||||||
volumeTextView.setText(String.valueOf(volume));
|
|
||||||
volumeMuteButton.clearColorFilter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private SeekBar.OnSeekBarChangeListener volumeSeekbarChangeListener = new SeekBar.OnSeekBarChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
|
||||||
if (fromUser) {
|
|
||||||
volumeTextView.setText(String.valueOf(progress));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
|
||||||
new Application.SetVolume(seekBar.getProgress())
|
|
||||||
.execute(hostManager.getConnection(), defaultIntActionCallback, callbackHandler);
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 Martijn Brekhof. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.xbmc.kore.ui.widgets;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.SeekBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.xbmc.kore.R;
|
||||||
|
|
||||||
|
public class VolumeLevelIndicator extends LinearLayout {
|
||||||
|
private SeekBar volumeSeekBar;
|
||||||
|
private TextView volumeTextView;
|
||||||
|
|
||||||
|
private OnVolumeChangeListener onVolumeChangeListener;
|
||||||
|
|
||||||
|
public interface OnVolumeChangeListener {
|
||||||
|
void onVolumeChanged(int volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VolumeLevelIndicator(Context context) {
|
||||||
|
super(context);
|
||||||
|
initializeView(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VolumeLevelIndicator(Context context, AttributeSet attributeSet) {
|
||||||
|
super(context, attributeSet);
|
||||||
|
initializeView(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeView(Context context) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
inflater.inflate(R.layout.volume_level_indicator, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFinishInflate() {
|
||||||
|
super.onFinishInflate();
|
||||||
|
|
||||||
|
volumeSeekBar = (SeekBar) findViewById(R.id.vli_seek_bar);
|
||||||
|
volumeTextView = (TextView) findViewById(R.id.vli_volume_text);
|
||||||
|
|
||||||
|
volumeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||||
|
if (fromUser)
|
||||||
|
volumeTextView.setText(String.valueOf(progress));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
|
if (onVolumeChangeListener != null)
|
||||||
|
onVolumeChangeListener.onVolumeChanged(seekBar.getProgress());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnVolumeChangeListener(OnVolumeChangeListener onVolumeChangeListener) {
|
||||||
|
this.onVolumeChangeListener = onVolumeChangeListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets UI volume state
|
||||||
|
* @param muted
|
||||||
|
* @param volume
|
||||||
|
*/
|
||||||
|
public void setVolume(boolean muted, int volume) {
|
||||||
|
if (muted) {
|
||||||
|
volumeTextView.setText(R.string.muted);
|
||||||
|
volumeSeekBar.setProgress(0);
|
||||||
|
} else {
|
||||||
|
volumeTextView.setText(String.valueOf(volume));
|
||||||
|
volumeSeekBar.setProgress(volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -561,13 +561,23 @@ public class UIUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void highlightImageView(Context context, ImageView view) {
|
/**
|
||||||
Resources.Theme theme = context.getTheme();
|
* Highlights an image view
|
||||||
TypedArray styledAttributes = theme.obtainStyledAttributes(new int[]{
|
* @param context
|
||||||
R.attr.colorAccent});
|
* @param view
|
||||||
view.setColorFilter(
|
* @param highlight true if the image view should be highlighted, false otherwise
|
||||||
styledAttributes.getColor(0,
|
*/
|
||||||
context.getResources().getColor(R.color.accent_default)));
|
public static void highlightImageView(Context context, ImageView view, boolean highlight) {
|
||||||
styledAttributes.recycle();
|
if (highlight) {
|
||||||
|
Resources.Theme theme = context.getTheme();
|
||||||
|
TypedArray styledAttributes = theme.obtainStyledAttributes(new int[]{
|
||||||
|
R.attr.colorAccent});
|
||||||
|
view.setColorFilter(
|
||||||
|
styledAttributes.getColor(styledAttributes.getIndex(0),
|
||||||
|
context.getResources().getColor(R.color.accent_default)));
|
||||||
|
styledAttributes.recycle();
|
||||||
|
} else {
|
||||||
|
view.clearColorFilter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,26 +169,12 @@
|
||||||
style="@style/Widget.Button.Borderless"
|
style="@style/Widget.Button.Borderless"
|
||||||
android:src="?attr/iconVolumeMute"
|
android:src="?attr/iconVolumeMute"
|
||||||
android:contentDescription="@string/volume_mute"/>
|
android:contentDescription="@string/volume_mute"/>
|
||||||
<LinearLayout
|
<org.xbmc.kore.ui.widgets.VolumeLevelIndicator
|
||||||
|
android:id="@+id/volume_level_indicator"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="2"
|
android:layout_weight="2"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"/>
|
||||||
<TextView
|
|
||||||
android:id="@+id/volume_text"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal|top"
|
|
||||||
style="@style/TextAppearance.Media.SmallDetails"
|
|
||||||
android:textSize="10sp"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/volume_bar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
style="@style/Widget.Button.Borderless"
|
|
||||||
android:layout_gravity="bottom"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/repeat"
|
android:id="@+id/repeat"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/vli_volume_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal|top"
|
||||||
|
style="@style/TextAppearance.Media.SmallDetails"
|
||||||
|
android:textSize="10sp"/>
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/vli_seek_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/Widget.Button.Borderless"
|
||||||
|
android:layout_gravity="bottom"/>
|
||||||
|
</merge>
|
Loading…
Reference in New Issue