Merge pull request #12952 from nextcloud/bugfix/media-control-view-visibility

Fix Media Control View Visibility
This commit is contained in:
Alper Öztürk 2024-05-02 13:52:32 +02:00 committed by GitHub
commit 361f9ddbb2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 429 additions and 390 deletions

View file

@ -1,343 +0,0 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2023 Alper Ozturk <alper_ozturk@proton.me>
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2018-2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2018 Andy Scherzinger <info@andy-scherzinger.de>
* SPDX-FileCopyrightText: 2015 ownCloud Inc.
* SPDX-FileCopyrightText: 2013 David A. Velasco <dvelasco@solidgear.es>
* SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
*/
package com.owncloud.android.media;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.LinearLayout;
import android.widget.MediaController.MediaPlayerControl;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.databinding.MediaControlBinding;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.utils.theme.ViewThemeUtils;
import java.util.Formatter;
import java.util.Locale;
import javax.inject.Inject;
/**
* View containing controls for a {@link MediaPlayer}.
* <p>
* Holds buttons "play / pause", "rewind", "fast forward" and a progress slider.
* <p>
* It synchronizes itself with the state of the {@link MediaPlayer}.
*/
public class MediaControlView extends LinearLayout implements OnClickListener, OnSeekBarChangeListener {
private static final String TAG = MediaControlView.class.getSimpleName();
private static final int SHOW_PROGRESS = 1;
private MediaPlayerControl playerControl;
private final MediaControlBinding binding;
private boolean isDragging;
@Inject
ViewThemeUtils viewThemeUtils;
public MediaControlView(Context context, AttributeSet attrs) {
super(context, attrs);
MainApp.getAppComponent().inject(this);
LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
binding = MediaControlBinding.inflate(inflate, this, true);
initControllerView();
setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
requestFocus();
}
@Override
public void onFinishInflate() {
super.onFinishInflate();
}
public void setMediaPlayer(MediaPlayerControl player) {
playerControl = player;
handler.sendEmptyMessage(SHOW_PROGRESS);
handler.postDelayed(() -> {
updatePausePlay();
setProgress();
}, 100);
}
public void stopMediaPlayerMessages() {
handler.removeMessages(SHOW_PROGRESS);
}
private void initControllerView() {
binding.playBtn.requestFocus();
binding.playBtn.setOnClickListener(this);
binding.forwardBtn.setOnClickListener(this);
binding.rewindBtn.setOnClickListener(this);
viewThemeUtils.platform.themeHorizontalSeekBar(binding.progressBar);
binding.progressBar.setOnSeekBarChangeListener(this);
binding.progressBar.setMax(1000);
}
/**
* Disable pause or seek buttons if the stream cannot be paused or seeked.
* This requires the control interface to be a MediaPlayerControlExt
*/
private void disableUnsupportedButtons() {
try {
if (binding != null) {
if (!playerControl.canPause()) {
binding.playBtn.setEnabled(false);
}
if (!playerControl.canSeekBackward()) {
binding.rewindBtn.setEnabled(false);
}
if (!playerControl.canSeekForward()) {
binding.forwardBtn.setEnabled(false);
}
}
} catch (IncompatibleClassChangeError ex) {
// We were given an old version of the interface, that doesn't have
// the canPause/canSeekXYZ methods. This is OK, it just means we
// assume the media can be paused and seeked, and so we don't disable
// the buttons.
Log_OC.i(TAG, "Old media interface detected");
}
}
private final Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what == SHOW_PROGRESS) {
updatePausePlay();
int pos = setProgress();
if (!isDragging) {
sendMessageDelayed(obtainMessage(SHOW_PROGRESS), 1000 - (pos % 1000));
}
}
}
};
private String formatTime(int timeMs) {
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
final StringBuilder mFormatBuilder = new StringBuilder();
final Formatter mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
if (hours > 0) {
return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
} else {
return mFormatter.format("%02d:%02d", minutes, seconds).toString();
}
}
private int setProgress() {
if (playerControl == null || isDragging) {
return 0;
}
int position = playerControl.getCurrentPosition();
int duration = playerControl.getDuration();
if (binding != null) {
if (duration > 0) {
// use long to avoid overflow
long pos = 1000L * position / duration;
binding.progressBar.setProgress((int) pos);
}
int percent = playerControl.getBufferPercentage();
binding.progressBar.setSecondaryProgress(percent * 10);
String endTime = duration > 0 ? formatTime(duration) : "--:--";
binding.totalTimeText.setText(endTime);
binding.currentTimeText.setText(formatTime(position));
}
return position;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
final boolean uniqueDown = event.getRepeatCount() == 0
&& event.getAction() == KeyEvent.ACTION_DOWN;
if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
|| keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
|| keyCode == KeyEvent.KEYCODE_SPACE) {
if (uniqueDown) {
doPauseResume();
//show(sDefaultTimeout);
if (binding != null) {
binding.playBtn.requestFocus();
}
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
if (uniqueDown && !playerControl.isPlaying()) {
playerControl.start();
updatePausePlay();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
|| keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
if (uniqueDown && playerControl.isPlaying()) {
playerControl.pause();
updatePausePlay();
}
return true;
}
return super.dispatchKeyEvent(event);
}
public void updatePausePlay() {
if (binding == null) {
return;
}
if (playerControl.isPlaying()) {
binding.playBtn.setImageResource(android.R.drawable.ic_media_pause);
} else {
binding.playBtn.setImageResource(android.R.drawable.ic_media_play);
}
final boolean canSeekFfd = playerControl.canSeekForward();
if (canSeekFfd) {
binding.forwardBtn.setVisibility(View.VISIBLE);
} else {
binding.forwardBtn.setVisibility(View.INVISIBLE);
}
final boolean canSeekBwd = playerControl.canSeekBackward();
if (canSeekBwd) {
binding.rewindBtn.setVisibility(View.VISIBLE);
} else {
binding.rewindBtn.setVisibility(View.INVISIBLE);
}
}
private void doPauseResume() {
if (playerControl.isPlaying()) {
playerControl.pause();
} else {
playerControl.start();
}
updatePausePlay();
}
@Override
public void setEnabled(boolean enabled) {
if(binding!=null){
binding.playBtn.setEnabled(enabled);
binding.forwardBtn.setEnabled(enabled);
binding.rewindBtn.setEnabled(enabled);
binding.progressBar.setEnabled(enabled);
}
disableUnsupportedButtons();
super.setEnabled(enabled);
}
@Override
public void onClick(View v) {
int pos;
boolean playing = playerControl.isPlaying();
int id = v.getId();
if (id == R.id.playBtn) {
doPauseResume();
} else if (id == R.id.rewindBtn) {
pos = playerControl.getCurrentPosition();
pos -= 5000;
playerControl.seekTo(pos);
if (!playing) {
playerControl.pause(); // necessary in some 2.3.x devices
}
setProgress();
} else if (id == R.id.forwardBtn) {
pos = playerControl.getCurrentPosition();
pos += 15000;
playerControl.seekTo(pos);
if (!playing) {
playerControl.pause(); // necessary in some 2.3.x devices
}
setProgress();
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (!fromUser) {
// We're not interested in programmatically generated changes to
// the progress bar's position.
return;
}
long duration = playerControl.getDuration();
long newPosition = (duration * progress) / 1000L;
playerControl.seekTo((int) newPosition);
binding.currentTimeText.setText(formatTime((int) newPosition));
}
/**
* Called in devices with touchpad when the user starts to adjust the position of the seekbar's thumb.
*
* Will be followed by several onProgressChanged notifications.
*/
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
isDragging = true; // monitors the duration of dragging
handler.removeMessages(SHOW_PROGRESS); // grants no more updates with media player progress while dragging
}
/**
* Called in devices with touchpad when the user finishes the adjusting of the seekbar.
*/
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
isDragging = false;
setProgress();
updatePausePlay();
handler.sendEmptyMessage(SHOW_PROGRESS); // grants future updates with media player progress
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(MediaControlView.class.getName());
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(MediaControlView.class.getName());
}
}

View file

@ -0,0 +1,347 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2023 Alper Ozturk <alper_ozturk@proton.me>
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2018-2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2018 Andy Scherzinger <info@andy-scherzinger.de>
* SPDX-FileCopyrightText: 2015 ownCloud Inc.
* SPDX-FileCopyrightText: 2013 David A. Velasco <dvelasco@solidgear.es>
* SPDX-License-Identifier: GPL-2.0-only AND AGPL-3.0-or-later
*/
package com.owncloud.android.media
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.LinearLayout
import android.widget.MediaController.MediaPlayerControl
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.core.content.ContextCompat
import com.owncloud.android.MainApp
import com.owncloud.android.R
import com.owncloud.android.databinding.MediaControlBinding
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.utils.theme.ViewThemeUtils
import java.util.Formatter
import java.util.Locale
import javax.inject.Inject
/**
* View containing controls for a MediaPlayer.
*
*
* Holds buttons "play / pause", "rewind", "fast forward" and a progress slider.
*
*
* It synchronizes itself with the state of the MediaPlayer.
*/
class MediaControlView(context: Context, attrs: AttributeSet?) :
LinearLayout(context, attrs),
View.OnClickListener,
OnSeekBarChangeListener {
private var playerControl: MediaPlayerControl? = null
private var binding: MediaControlBinding
private var isDragging = false
@Inject
lateinit var viewThemeUtils: ViewThemeUtils
public override fun onFinishInflate() {
super.onFinishInflate()
}
@Suppress("MagicNumber")
fun setMediaPlayer(player: MediaPlayerControl?) {
playerControl = player
handler.sendEmptyMessage(SHOW_PROGRESS)
handler.postDelayed({
updatePausePlay()
setProgress()
}, 100)
}
fun stopMediaPlayerMessages() {
handler.removeMessages(SHOW_PROGRESS)
}
@Suppress("MagicNumber")
private fun initControllerView() {
binding.playBtn.requestFocus()
binding.playBtn.setOnClickListener(this)
binding.forwardBtn.setOnClickListener(this)
binding.rewindBtn.setOnClickListener(this)
binding.progressBar.run {
viewThemeUtils.platform.themeHorizontalSeekBar(this)
setMax(1000)
}
binding.progressBar.setOnSeekBarChangeListener(this)
viewThemeUtils.material.run {
colorMaterialButtonPrimaryTonal(binding.rewindBtn)
colorMaterialButtonPrimaryTonal(binding.playBtn)
colorMaterialButtonPrimaryTonal(binding.forwardBtn)
}
}
/**
* Disable pause or seek buttons if the stream cannot be paused or seeked.
* This requires the control interface to be a MediaPlayerControlExt
*/
private fun disableUnsupportedButtons() {
try {
if (playerControl?.canPause() == false) {
binding.playBtn.setEnabled(false)
}
if (playerControl?.canSeekBackward() == false) {
binding.rewindBtn.setEnabled(false)
}
if (playerControl?.canSeekForward() == false) {
binding.forwardBtn.setEnabled(false)
}
} catch (ex: IncompatibleClassChangeError) {
// We were given an old version of the interface, that doesn't have
// the canPause/canSeekXYZ methods. This is OK, it just means we
// assume the media can be paused and seeked, and so we don't disable
// the buttons.
Log_OC.i(TAG, "Old media interface detected")
}
}
@Suppress("MagicNumber")
private val handler: Handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
if (msg.what == SHOW_PROGRESS) {
updatePausePlay()
val pos = setProgress()
if (!isDragging) {
sendMessageDelayed(obtainMessage(SHOW_PROGRESS), (1000 - pos % 1000).toLong())
}
}
}
}
init {
MainApp.getAppComponent().inject(this)
val inflate = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
binding = MediaControlBinding.inflate(inflate, this, true)
initControllerView()
isFocusable = true
setFocusableInTouchMode(true)
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS)
requestFocus()
}
@Suppress("MagicNumber")
private fun formatTime(timeMs: Int): String {
val totalSeconds = timeMs / 1000
val seconds = totalSeconds % 60
val minutes = totalSeconds / 60 % 60
val hours = totalSeconds / 3600
val mFormatBuilder = StringBuilder()
val mFormatter = Formatter(mFormatBuilder, Locale.getDefault())
return if (hours > 0) {
mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString()
} else {
mFormatter.format("%02d:%02d", minutes, seconds).toString()
}
}
@Suppress("MagicNumber")
private fun setProgress(): Int {
var position = 0
if (playerControl == null || isDragging) {
position = 0
}
playerControl?.let { playerControl ->
position = playerControl.currentPosition
val duration = playerControl.duration
if (duration > 0) {
// use long to avoid overflow
val pos = 1000L * position / duration
binding.progressBar.progress = pos.toInt()
}
val percent = playerControl.bufferPercentage
binding.progressBar.setSecondaryProgress(percent * 10)
val endTime = if (duration > 0) formatTime(duration) else "--:--"
binding.totalTimeText.text = endTime
binding.currentTimeText.text = formatTime(position)
}
return position
}
@Suppress("ReturnCount")
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
val keyCode = event.keyCode
val uniqueDown = (event.repeatCount == 0 && event.action == KeyEvent.ACTION_DOWN)
when (keyCode) {
KeyEvent.KEYCODE_HEADSETHOOK, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_SPACE -> {
if (uniqueDown) {
doPauseResume()
// show(sDefaultTimeout);
binding.playBtn.requestFocus()
}
return true
}
KeyEvent.KEYCODE_MEDIA_PLAY -> {
if (uniqueDown && playerControl?.isPlaying == false) {
playerControl?.start()
updatePausePlay()
}
return true
}
KeyEvent.KEYCODE_MEDIA_STOP,
KeyEvent.KEYCODE_MEDIA_PAUSE
-> {
if (uniqueDown && playerControl?.isPlaying == true) {
playerControl?.pause()
updatePausePlay()
}
return true
}
else -> return super.dispatchKeyEvent(event)
}
}
fun updatePausePlay() {
binding.playBtn.icon = ContextCompat.getDrawable(
context,
if (playerControl?.isPlaying == true) {
R.drawable.ic_pause
} else { R.drawable.ic_play }
)
binding.forwardBtn.visibility = if (playerControl?.canSeekForward() == true) { VISIBLE } else { INVISIBLE }
binding.rewindBtn.visibility = if (playerControl?.canSeekBackward() == true) { VISIBLE } else { INVISIBLE }
}
private fun doPauseResume() {
playerControl?.run {
if (isPlaying) {
pause()
} else {
start()
}
}
updatePausePlay()
}
override fun setEnabled(enabled: Boolean) {
binding.playBtn.setEnabled(enabled)
binding.forwardBtn.setEnabled(enabled)
binding.rewindBtn.setEnabled(enabled)
binding.progressBar.setEnabled(enabled)
disableUnsupportedButtons()
super.setEnabled(enabled)
}
@Suppress("MagicNumber")
override fun onClick(v: View) {
var pos: Int
playerControl?.let { playerControl ->
val playing = playerControl.isPlaying
val id = v.id
when (id) {
R.id.playBtn -> {
doPauseResume()
}
R.id.rewindBtn -> {
pos = playerControl.currentPosition
pos -= 5000
playerControl.seekTo(pos)
if (!playing) {
playerControl.pause() // necessary in some 2.3.x devices
}
setProgress()
}
R.id.forwardBtn -> {
pos = playerControl.currentPosition
pos += 15000
playerControl.seekTo(pos)
if (!playing) {
playerControl.pause() // necessary in some 2.3.x devices
}
setProgress()
}
else -> {
}
}
}
}
@Suppress("MagicNumber")
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (!fromUser) {
// We're not interested in programmatically generated changes to
// the progress bar's position.
return
}
playerControl?.let { playerControl ->
val duration = playerControl.duration.toLong()
val newPosition = duration * progress / 1000L
playerControl.seekTo(newPosition.toInt())
binding.currentTimeText.text = formatTime(newPosition.toInt())
}
}
/**
* Called in devices with touchpad when the user starts to adjust the position of the seekbar's thumb.
*
* Will be followed by several onProgressChanged notifications.
*/
override fun onStartTrackingTouch(seekBar: SeekBar) {
isDragging = true // monitors the duration of dragging
handler.removeMessages(SHOW_PROGRESS) // grants no more updates with media player progress while dragging
}
/**
* Called in devices with touchpad when the user finishes the adjusting of the seekbar.
*/
override fun onStopTrackingTouch(seekBar: SeekBar) {
isDragging = false
setProgress()
updatePausePlay()
handler.sendEmptyMessage(SHOW_PROGRESS) // grants future updates with media player progress
}
override fun onInitializeAccessibilityEvent(event: AccessibilityEvent) {
super.onInitializeAccessibilityEvent(event)
event.setClassName(MediaControlView::class.java.getName())
}
override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo) {
super.onInitializeAccessibilityNodeInfo(info)
info.setClassName(MediaControlView::class.java.getName())
}
companion object {
private val TAG = MediaControlView::class.java.getSimpleName()
private const val SHOW_PROGRESS = 1
}
}

View file

@ -0,0 +1,15 @@
<!--
~ Nextcloud - Android Client
~
~ SPDX-FileCopyrightText: 2018-2024 Google LLC
~ SPDX-License-Identifier: Apache-2.0
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M100,720v-480l360,240 -360,240ZM500,720v-480l360,240 -360,240Z"/>
</vector>

View file

@ -0,0 +1,15 @@
<!--
~ Nextcloud - Android Client
~
~ SPDX-FileCopyrightText: 2018-2024 Google LLC
~ SPDX-License-Identifier: Apache-2.0
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M860,720 L500,480l360,-240v480ZM460,720L100,480l360,-240v480Z"/>
</vector>

View file

@ -9,7 +9,7 @@
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@color/foreground_highlight"
android:pathData="M560,760L560,200L720,200L720,760L560,760ZM240,760L240,200L400,200L400,760L240,760Z" />
<path
android:fillColor="#FF000000"
android:pathData="M360,640h80v-320h-80v320ZM520,640h80v-320h-80v320ZM480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880Z"/>
</vector>

View file

@ -1,9 +1,8 @@
<!--
~ Nextcloud - Android Client
~
~ SPDX-FileCopyrightText: 2023 Alper Ozturk <alper_ozturk@proton.me>
~ SPDX-FileCopyrightText: 2023 Nextcloud GmbH
~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
~ SPDX-FileCopyrightText: 2018-2024 Google LLC
~ SPDX-License-Identifier: Apache-2.0
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
@ -11,6 +10,6 @@
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@color/foreground_highlight"
android:pathData="M320,760v-560l440,280 -440,280Z"/>
android:fillColor="#FF000000"
android:pathData="m380,660 l280,-180 -280,-180v360ZM480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880Z"/>
</vector>

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Nextcloud - Android Client
~
~ SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
~ SPDX-FileCopyrightText: 2022 Nextcloud GmbH
~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/grey_200">
<item android:id="@android:id/mask">
<shape android:shape="oval">
<solid android:color="?android:colorPrimary" />
</shape>
<color android:color="@color/white" />
</item>
</ripple>

View file

@ -7,49 +7,76 @@
~ SPDX-FileCopyrightText: 2013 David A. Velasco <dvelasco@solidgear.es>
~ SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
android:id="@+id/media_control_linear_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_marginBottom="@dimen/standard_double_margin"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="50dp"
android:gravity="center"
android:orientation="horizontal"
android:paddingTop="@dimen/standard_quarter_padding">
<ImageButton
<com.google.android.material.button.MaterialButton
android:id="@+id/rewindBtn"
style="@android:style/MediaButton.Rew"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
app:backgroundTint="@color/transparent"
app:iconTint="@color/black"
app:iconGravity="top"
android:layout_marginEnd="@dimen/standard_half_margin"
android:paddingTop="@dimen/alternate_padding"
app:icon="@drawable/ic_fast_rewind"
android:contentDescription="@string/media_rewind_description" />
<ImageButton
<com.google.android.material.button.MaterialButton
android:id="@+id/playBtn"
style="@android:style/MediaButton.Play"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
app:backgroundTint="@color/transparent"
app:iconTint="@color/black"
app:iconGravity="top"
android:paddingTop="@dimen/alternate_padding"
app:icon="@drawable/ic_play"
android:layout_marginEnd="@dimen/standard_half_margin"
android:contentDescription="@string/media_play_pause_description" />
<ImageButton
<com.google.android.material.button.MaterialButton
android:id="@+id/forwardBtn"
style="@android:style/MediaButton.Ffwd"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
app:backgroundTint="@color/transparent"
app:iconTint="@color/black"
app:iconGravity="top"
android:paddingTop="@dimen/alternate_padding"
app:icon="@drawable/ic_fast_forward"
android:contentDescription="@string/media_forward_description" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="50dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/currentTimeText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingStart="@dimen/standard_quarter_padding"
android:paddingTop="@dimen/standard_quarter_padding"
android:paddingEnd="@dimen/standard_quarter_padding"
android:layout_height="match_parent"
android:padding="@dimen/standard_quarter_padding"
android:gravity="center"
android:text="@string/placeholder_media_time"
android:textColor="@color/text_color"
android:textSize="@dimen/two_line_secondary_text_size"
@ -59,7 +86,7 @@
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="@dimen/seek_bar_height"
android:layout_height="match_parent"
android:layout_weight="1"
android:splitTrack="false"
tools:ignore="UnusedAttribute" />
@ -67,11 +94,9 @@
<TextView
android:id="@+id/totalTimeText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingStart="@dimen/standard_quarter_padding"
android:paddingTop="@dimen/standard_quarter_padding"
android:paddingEnd="@dimen/standard_quarter_padding"
android:layout_height="match_parent"
android:padding="@dimen/standard_quarter_padding"
android:gravity="center"
android:text="@string/placeholder_media_time"
android:textColor="@color/text_color"
android:textSize="@dimen/two_line_secondary_text_size"

View file

@ -53,7 +53,6 @@
<color name="nc_grey">#ededed</color>
<color name="icon_on_nc_grey">#000000</color>
<color name="foreground_highlight">#1D1B1E</color>
<color name="process_dialog_background">#ffffff</color>
<color name="indicator_dot_selected">#ffffff</color>
<color name="drawer_shadow">#000000</color>

View file

@ -78,7 +78,6 @@
<dimen name="file_download_fragment_display_text_margin">40dp</dimen>
<dimen name="drawer_width">240dp</dimen>
<dimen name="grid_item_text_size">16sp</dimen>
<dimen name="seek_bar_height">32dp</dimen>
<dimen name="search_users_groups_layout_width">200dp</dimen>
<dimen name="search_users_groups_layout_list_view_margin">20dp</dimen>
<dimen name="share_file_layout_text_size">12sp</dimen>