diff --git a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt index b28968f45..a7dc511db 100644 --- a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt +++ b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt @@ -83,6 +83,7 @@ object PreferenceKeys { const val ALTERNATIVE_PLAYER_LAYOUT = "alternative_player_layout" const val USE_HLS_OVER_DASH = "use_hls" const val QUEUE_AUTO_INSERT_RELATED = "queue_insert_related_videos" + const val PLAYER_SWIPE_CONTROLS = "player_swipe_controls" /** * Background mode diff --git a/app/src/main/java/com/github/libretube/extensions/Normalize.kt b/app/src/main/java/com/github/libretube/extensions/Normalize.kt new file mode 100644 index 000000000..0550a62c0 --- /dev/null +++ b/app/src/main/java/com/github/libretube/extensions/Normalize.kt @@ -0,0 +1,15 @@ +package com.github.libretube.extensions + +fun Int.normalize(oldMin: Int, oldMax: Int, newMin: Int, newMax: Int): Int { + val oldRange = oldMax - oldMin + val newRange = newMax - newMin + + return (this - oldMin) * newRange / oldRange + newMin +} + +fun Float.normalize(oldMin: Float, oldMax: Float, newMin: Float, newMax: Float): Float { + val oldRange = oldMax - oldMin + val newRange = newMax - newMin + + return (this - oldMin) * newRange / oldRange + newMin +} diff --git a/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt b/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt index 4f6d26638..1bdd22255 100644 --- a/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt +++ b/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt @@ -70,6 +70,7 @@ class OfflinePlayerActivity : BaseActivity() { binding.player.initialize( null, binding.doubleTapOverlay.binding, + binding.playerGestureControlsView.binding, null ) } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index 9d5fc24fc..d0c224963 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -49,6 +49,7 @@ import com.github.libretube.constants.PreferenceKeys import com.github.libretube.databinding.DoubleTapOverlayBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding import com.github.libretube.databinding.FragmentPlayerBinding +import com.github.libretube.databinding.PlayerGestureControlsViewBinding import com.github.libretube.db.DatabaseHelper import com.github.libretube.db.DatabaseHolder.Companion.Database import com.github.libretube.db.obj.WatchPosition @@ -118,6 +119,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { lateinit var binding: FragmentPlayerBinding private lateinit var playerBinding: ExoStyledPlayerControlViewBinding private lateinit var doubleTapOverlayBinding: DoubleTapOverlayBinding + private lateinit var playerGestureControlsViewBinding: PlayerGestureControlsViewBinding private val viewModel: PlayerViewModel by activityViewModels() /** @@ -183,6 +185,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { exoPlayerView = binding.player playerBinding = binding.player.binding doubleTapOverlayBinding = binding.doubleTapOverlay.binding + playerGestureControlsViewBinding = binding.playerGestureControlsView.binding // Inflate the layout for this fragment return binding.root @@ -775,6 +778,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { binding.player.initialize( this, doubleTapOverlayBinding, + playerGestureControlsViewBinding, trackSelector ) diff --git a/app/src/main/java/com/github/libretube/ui/interfaces/DoubleTapListener.kt b/app/src/main/java/com/github/libretube/ui/interfaces/DoubleTapListener.kt deleted file mode 100644 index 24fd9b1eb..000000000 --- a/app/src/main/java/com/github/libretube/ui/interfaces/DoubleTapListener.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.github.libretube.ui.interfaces - -import android.os.Handler -import android.os.Looper -import android.os.SystemClock -import android.view.View - -abstract class DoubleTapListener : View.OnClickListener { - - private val handler = Handler(Looper.getMainLooper()) - - private var lastClick = 0L - private var lastDoubleClick = 0L - - abstract fun onDoubleClick() - abstract fun onSingleClick() - - override fun onClick(v: View?) { - if (isSecondClick()) { - handler.removeCallbacks(runnable) - lastDoubleClick = elapsedTime() - onDoubleClick() - } else { - if (recentDoubleClick()) return - handler.removeCallbacks(runnable) - handler.postDelayed(runnable, MAX_TIME_DIFF) - lastClick = elapsedTime() - } - } - - private val runnable = Runnable { - if (isSecondClick()) return@Runnable - onSingleClick() - } - - private fun isSecondClick(): Boolean { - return elapsedTime() - lastClick < MAX_TIME_DIFF - } - - private fun recentDoubleClick(): Boolean { - return elapsedTime() - lastDoubleClick < MAX_TIME_DIFF / 2 - } - - fun elapsedTime() = SystemClock.elapsedRealtime() - - companion object { - private const val MAX_TIME_DIFF = 400L - } -} diff --git a/app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt b/app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt new file mode 100644 index 000000000..ee6e60dd1 --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt @@ -0,0 +1,18 @@ +package com.github.libretube.ui.interfaces + +interface PlayerGestureOptions { + + fun onSingleTap() + + fun onDoubleTapCenterScreen() + + fun onDoubleTapLeftScreen() + + fun onDoubleTapRightScreen() + + fun onSwipeLeftScreen(distanceY: Float) + + fun onSwipeRightScreen(distanceY: Float) + + fun onSwipeEnd() +} diff --git a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt index dd51ca16f..c46ad917a 100644 --- a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt +++ b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt @@ -1,6 +1,7 @@ package com.github.libretube.ui.views import android.annotation.SuppressLint +import android.app.Activity import android.content.Context import android.content.res.Configuration import android.os.Handler @@ -8,18 +9,24 @@ import android.os.Looper import android.util.AttributeSet import android.view.MotionEvent import android.view.View +import android.view.WindowManager import com.github.libretube.R import com.github.libretube.databinding.DoubleTapOverlayBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding +import com.github.libretube.databinding.PlayerGestureControlsViewBinding +import com.github.libretube.extensions.normalize import com.github.libretube.extensions.toDp import com.github.libretube.obj.BottomSheetItem import com.github.libretube.ui.activities.MainActivity import com.github.libretube.ui.base.BaseActivity -import com.github.libretube.ui.interfaces.DoubleTapListener import com.github.libretube.ui.interfaces.OnlinePlayerOptions +import com.github.libretube.ui.interfaces.PlayerGestureOptions import com.github.libretube.ui.interfaces.PlayerOptions import com.github.libretube.ui.sheets.BaseBottomSheet import com.github.libretube.ui.sheets.PlaybackSpeedSheet +import com.github.libretube.util.AudioHelper +import com.github.libretube.util.BrightnessHelper +import com.github.libretube.util.PlayerGestureController import com.github.libretube.util.PlayerHelper import com.github.libretube.util.PlayingQueue import com.google.android.exoplayer2.PlaybackParameters @@ -33,8 +40,16 @@ import com.google.android.exoplayer2.util.RepeatModeUtil internal class CustomExoPlayerView( context: Context, attributeSet: AttributeSet? = null -) : StyledPlayerView(context, attributeSet), PlayerOptions { +) : StyledPlayerView(context, attributeSet), PlayerOptions, PlayerGestureOptions { val binding: ExoStyledPlayerControlViewBinding = ExoStyledPlayerControlViewBinding.bind(this) + + /** + * Objects for player tap and swipe gesture + */ + private lateinit var gestureViewBinding: PlayerGestureControlsViewBinding + private lateinit var playerGestureController: PlayerGestureController + private lateinit var brightnessHelper: BrightnessHelper + private lateinit var audioHelper: AudioHelper private var doubleTapOverlayBinding: DoubleTapOverlayBinding? = null /** @@ -45,16 +60,12 @@ internal class CustomExoPlayerView( private val runnableHandler = Handler(Looper.getMainLooper()) - // the x-position of where the user clicked - private var xPos = 0F - var isPlayerLocked: Boolean = false /** * Preferences */ var autoplayEnabled = PlayerHelper.autoPlayEnabled - private var doubleTapAllowed = true private var resizeModePref = PlayerHelper.resizeModePref @@ -65,42 +76,23 @@ internal class CustomExoPlayerView( if (isControllerFullyVisible) hideController() else showController() } - private val doubleTouchListener = object : DoubleTapListener() { - override fun onDoubleClick() { - if (!doubleTapAllowed) return - val eventPositionPercentageX = xPos / width - when { - eventPositionPercentageX < 0.4 -> rewind() - eventPositionPercentageX > 0.6 -> forward() - else -> { - player?.let { player -> - if (player.isPlaying) { - player.pause() - } else { - player.play() - } - } - } - } - } - - override fun onSingleClick() { - toggleController() - } - } - fun initialize( playerViewInterface: OnlinePlayerOptions?, doubleTapOverlayBinding: DoubleTapOverlayBinding, + playerGestureControlsViewBinding: PlayerGestureControlsViewBinding, trackSelector: TrackSelector? ) { this.playerOptionsInterface = playerViewInterface this.doubleTapOverlayBinding = doubleTapOverlayBinding this.trackSelector = trackSelector + this.gestureViewBinding = playerGestureControlsViewBinding + this.playerGestureController = PlayerGestureController(context, this) + this.brightnessHelper = BrightnessHelper(context as Activity) + this.audioHelper = AudioHelper(context) - // set the double click listener for rewind/forward - setOnClickListener(doubleTouchListener) - + // Set touch listner for tap and swipe gestures. + setOnTouchListener(playerGestureController) + initializeGestureProgress() enableDoubleTapToSeek() initializeAdvancedOptions(context) @@ -144,10 +136,6 @@ internal class CustomExoPlayerView( } override fun onTouchEvent(event: MotionEvent): Boolean { - // save the x position of the touch event - xPos = event.x - // listen for a double touch - doubleTouchListener.onClick(this) return false } @@ -261,8 +249,8 @@ internal class CustomExoPlayerView( binding.exoBottomBar.visibility = visibility binding.closeImageButton.visibility = visibility - // disable double tap to seek if the player is locked - doubleTapAllowed = !isLocked + // disable tap and swipe gesture if the player is locked + playerGestureController.isEnabled = isLocked } private fun enableDoubleTapToSeek() { @@ -331,6 +319,56 @@ internal class CustomExoPlayerView( } } + private fun initializeGestureProgress() { + val brightnessBar = gestureViewBinding.brightnessProgressBar + val volumeBar = gestureViewBinding.volumeProgressBar + + brightnessBar.progress = if (brightnessHelper.brightness == WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE) { + 25.normalize(0, 100, 0, volumeBar.max) + } else { + brightnessHelper.getBrightnessWithScale(brightnessBar.max.toFloat()).toInt() + } + volumeBar.progress = audioHelper.getVolumeWithScale(volumeBar.max) + } + + private fun updateBrightness(distance: Float) { + gestureViewBinding.brightnessControlView.visibility = View.VISIBLE + val bar = gestureViewBinding.brightnessProgressBar + + if (bar.progress == 0) { + // If brightness progress goes to below 0, set to system brightness + if (distance <= 0) { + brightnessHelper.resetToSystemBrightness() + gestureViewBinding.brightnessImageView.setImageResource(R.drawable.ic_brightness_auto) + gestureViewBinding.brightnessTextView.text = resources.getString(R.string.auto) + return + } + gestureViewBinding.brightnessImageView.setImageResource(R.drawable.ic_brightness) + } + + bar.incrementProgressBy(distance.toInt()) + gestureViewBinding.brightnessTextView.text = "${bar.progress.normalize(0, bar.max, 0, 100)}" + brightnessHelper.setBrightnessWithScale(bar.progress.toFloat(), bar.max.toFloat()) + } + + private fun updateVolume(distance: Float) { + gestureViewBinding.volumeControlView.visibility = View.VISIBLE + val bar = gestureViewBinding.volumeProgressBar + + if (bar.progress == 0) { + gestureViewBinding.volumeImageView.setImageResource( + when { + distance > 0 -> R.drawable.ic_volume_up + else -> R.drawable.ic_volume_off + } + ) + } + bar.incrementProgressBy(distance.toInt()) + audioHelper.setVolumeWithScale(bar.progress, bar.max) + + gestureViewBinding.volumeTextView.text = "${bar.progress.normalize(0, bar.max, 0, 100)}" + } + override fun onAutoplayClicked() { // autoplay options dialog BaseBottomSheet() @@ -408,4 +446,47 @@ internal class CustomExoPlayerView( it.layoutParams = params } } + + override fun onSingleTap() { + toggleController() + } + + override fun onDoubleTapCenterScreen() { + player?.let { player -> + if (player.isPlaying) { + player.pause() + if (!isControllerFullyVisible) showController() + } else { + player.play() + if (isControllerFullyVisible) hideController() + } + } + } + + override fun onDoubleTapLeftScreen() { + rewind() + } + + override fun onDoubleTapRightScreen() { + forward() + } + + override fun onSwipeLeftScreen(distanceY: Float) { + if (!PlayerHelper.swipeGestureEnabled || resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) return + + if (isControllerFullyVisible) hideController() + updateBrightness(distanceY) + } + + override fun onSwipeRightScreen(distanceY: Float) { + if (!PlayerHelper.swipeGestureEnabled || resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) return + + if (isControllerFullyVisible) hideController() + updateVolume(distanceY) + } + + override fun onSwipeEnd() { + gestureViewBinding.brightnessControlView.visibility = View.GONE + gestureViewBinding.volumeControlView.visibility = View.GONE + } } diff --git a/app/src/main/java/com/github/libretube/ui/views/PlayerGestureControlsView.kt b/app/src/main/java/com/github/libretube/ui/views/PlayerGestureControlsView.kt new file mode 100644 index 000000000..8e3ac3fd7 --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/views/PlayerGestureControlsView.kt @@ -0,0 +1,26 @@ +package com.github.libretube.ui.views + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.constraintlayout.widget.ConstraintLayout +import com.github.libretube.databinding.PlayerGestureControlsViewBinding + +class PlayerGestureControlsView( + context: Context, + attrs: AttributeSet? = null +) : ConstraintLayout(context, attrs) { + var binding: PlayerGestureControlsViewBinding + + init { + val layoutInflater = LayoutInflater.from(context) + binding = PlayerGestureControlsViewBinding.inflate(layoutInflater, this, true) + } + + override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) { + super.onSizeChanged(width, height, oldHeight, oldHeight) + + binding.brightnessProgressBar.max = (height * 0.7).toInt() + binding.volumeProgressBar.max = (height * 0.7).toInt() + } +} diff --git a/app/src/main/java/com/github/libretube/util/AudioHelper.kt b/app/src/main/java/com/github/libretube/util/AudioHelper.kt new file mode 100644 index 000000000..603933cd5 --- /dev/null +++ b/app/src/main/java/com/github/libretube/util/AudioHelper.kt @@ -0,0 +1,50 @@ +package com.github.libretube.util + +import android.content.Context +import android.media.AudioManager +import android.os.Build +import androidx.core.math.MathUtils +import com.github.libretube.extensions.normalize + +class AudioHelper( + context: Context, + private val stream: Int = AudioManager.STREAM_MUSIC +) { + + private lateinit var audioManager: AudioManager + private var minimumVolumeIndex = 0 + private var maximumVolumeIndex = 16 + + init { + (context.getSystemService(Context.AUDIO_SERVICE) as? AudioManager)?.let { + audioManager = it + maximumVolumeIndex = it.getStreamMaxVolume(stream) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + minimumVolumeIndex = it.getStreamMinVolume(stream) + } + } + } + + var volume: Int + get() { + return if (this::audioManager.isInitialized) { + audioManager.getStreamVolume(stream) - minimumVolumeIndex + } else { + 0 + } + } + set(value) { + if (this::audioManager.isInitialized) { + val vol = MathUtils.clamp(value, minimumVolumeIndex, maximumVolumeIndex) + audioManager.setStreamVolume(stream, vol, 0) + } + } + + fun setVolumeWithScale(value: Int, maxValue: Int, minValue: Int = 0) { + volume = value.normalize(minValue, maxValue, minimumVolumeIndex, maximumVolumeIndex) + } + + fun getVolumeWithScale(maxValue: Int, minValue: Int = 0): Int { + return volume.normalize(minimumVolumeIndex, maximumVolumeIndex, minValue, maxValue) + } +} diff --git a/app/src/main/java/com/github/libretube/util/BrightnessHelper.kt b/app/src/main/java/com/github/libretube/util/BrightnessHelper.kt new file mode 100644 index 000000000..e03581191 --- /dev/null +++ b/app/src/main/java/com/github/libretube/util/BrightnessHelper.kt @@ -0,0 +1,38 @@ +package com.github.libretube.util + +import android.app.Activity +import android.view.WindowManager +import com.github.libretube.extensions.normalize + +class BrightnessHelper(activity: Activity) { + + private val window = activity.window + private val minBrightness = 0.0f + private val maxBrightness = 1.0f + + /** + * Wrapper for the current screen brightness + */ + var brightness: Float + get() = window.attributes.screenBrightness + private set(value) { + val lp = window.attributes + lp.screenBrightness = value + window.attributes = lp + } + + /** + * Restore screen brightness to device system brightness. + */ + fun resetToSystemBrightness() { + brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE + } + + fun setBrightnessWithScale(value: Float, maxValue: Float, minValue: Float = 0.0f) { + brightness = value.normalize(minValue, maxValue, minBrightness, maxBrightness) + } + + fun getBrightnessWithScale(maxValue: Float, minValue: Float = 0.0f): Float { + return brightness.normalize(minBrightness, maxBrightness, minValue, maxValue) + } +} diff --git a/app/src/main/java/com/github/libretube/util/PlayerGestureController.kt b/app/src/main/java/com/github/libretube/util/PlayerGestureController.kt new file mode 100644 index 000000000..d647306b8 --- /dev/null +++ b/app/src/main/java/com/github/libretube/util/PlayerGestureController.kt @@ -0,0 +1,130 @@ +package com.github.libretube.util + +import android.annotation.SuppressLint +import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources +import android.os.Handler +import android.os.Looper +import android.os.SystemClock +import android.view.GestureDetector +import android.view.MotionEvent +import android.view.View +import com.github.libretube.ui.interfaces.PlayerGestureOptions +import kotlin.math.abs + +class PlayerGestureController(context: Context, private val listner: PlayerGestureOptions) : + View.OnTouchListener { + + // width and height should be obtained each time using getter to adopt layout size changes. + private val width get() = Resources.getSystem().displayMetrics.widthPixels + private val height get() = Resources.getSystem().displayMetrics.heightPixels + private val orientation get() = Resources.getSystem().configuration.orientation + private val elapsedTime get() = SystemClock.elapsedRealtime() + + private val handler: Handler = Handler(Looper.getMainLooper()) + private val gestureDetector: GestureDetector + private var isMoving = false + var isEnabled = true + + init { + gestureDetector = GestureDetector(context, GestureListener(), handler) + } + + @SuppressLint("ClickableViewAccessibility") + override fun onTouch(v: View, event: MotionEvent): Boolean { + if (event.action == MotionEvent.ACTION_UP && isMoving) { + isMoving = false + listner.onSwipeEnd() + } + + // Event can be already consumed by some view which may lead to NPE. + try { + gestureDetector.onTouchEvent(event) + } catch (_: Exception) { } + + // If orientation is landscape then allow `onScroll` to consume event and return true. + return orientation == Configuration.ORIENTATION_LANDSCAPE + } + + private inner class GestureListener : GestureDetector.SimpleOnGestureListener() { + private var lastClick = 0L + private var lastDoubleClick = 0L + private var xPos = 0.0F + + override fun onDown(e: MotionEvent): Boolean { + if (isMoving) return false + + if (isEnabled && isSecondClick()) { + handler.removeCallbacks(runnable) + lastDoubleClick = elapsedTime + val eventPositionPercentageX = xPos / width + + when { + eventPositionPercentageX < 0.4 -> listner.onDoubleTapLeftScreen() + eventPositionPercentageX > 0.6 -> listner.onDoubleTapRightScreen() + else -> listner.onDoubleTapCenterScreen() + } + } else { + if (recentDoubleClick()) return true + handler.removeCallbacks(runnable) + handler.postDelayed(runnable, MAX_TIME_DIFF) + lastClick = elapsedTime + xPos = e.x + } + return true + } + + override fun onScroll( + e1: MotionEvent, + e2: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean { + if (!isEnabled) return false + + val insideThreshHold = abs(e2.y - e1.y) <= MOVEMENT_THRESHOLD + val insideBorder = (e1.x < BORDER_THRESHOLD || e1.y < BORDER_THRESHOLD || e1.x > width - BORDER_THRESHOLD || e1.y > height - BORDER_THRESHOLD) + + // If the movement is inside threshold or scroll is horizontal then return false + if ( + !isMoving && ( + insideThreshHold || insideBorder || + abs(distanceX) > abs( + distanceY + ) + ) + ) { + return false + } + + isMoving = true + + when { + width * 0.5 > e1.x -> listner.onSwipeLeftScreen(distanceY) + width * 0.5 < e1.x -> listner.onSwipeRightScreen(distanceY) + } + return true + } + + private val runnable = Runnable { + // If user is scrolling then avoid single tap call + if (isMoving || isSecondClick()) return@Runnable + listner.onSingleTap() + } + + private fun isSecondClick(): Boolean { + return elapsedTime - lastClick < MAX_TIME_DIFF + } + + private fun recentDoubleClick(): Boolean { + return elapsedTime - lastDoubleClick < MAX_TIME_DIFF / 2 + } + } + + companion object { + private const val MAX_TIME_DIFF = 400L + private const val MOVEMENT_THRESHOLD = 30 + private const val BORDER_THRESHOLD = 90 + } +} diff --git a/app/src/main/java/com/github/libretube/util/PlayerHelper.kt b/app/src/main/java/com/github/libretube/util/PlayerHelper.kt index 346bb854d..177665efc 100644 --- a/app/src/main/java/com/github/libretube/util/PlayerHelper.kt +++ b/app/src/main/java/com/github/libretube/util/PlayerHelper.kt @@ -294,6 +294,12 @@ object PlayerHelper { true ) + val swipeGestureEnabled: Boolean + get() = PreferenceHelper.getBoolean( + PreferenceKeys.PLAYER_SWIPE_CONTROLS, + true + ) + fun getDefaultResolution(context: Context): String { return if (NetworkHelper.isNetworkMobile(context)) { PreferenceHelper.getString( diff --git a/app/src/main/res/drawable/controls_layout_bg.xml b/app/src/main/res/drawable/controls_layout_bg.xml new file mode 100644 index 000000000..9e7c439b7 --- /dev/null +++ b/app/src/main/res/drawable/controls_layout_bg.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_brightness.xml b/app/src/main/res/drawable/ic_brightness.xml new file mode 100644 index 000000000..ecf23dfb9 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_auto.xml b/app/src/main/res/drawable/ic_brightness_auto.xml new file mode 100644 index 000000000..aa74c4915 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_auto.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_swipe_gesture.xml b/app/src/main/res/drawable/ic_swipe_gesture.xml new file mode 100644 index 000000000..f10107b2e --- /dev/null +++ b/app/src/main/res/drawable/ic_swipe_gesture.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_volume_off.xml b/app/src/main/res/drawable/ic_volume_off.xml new file mode 100644 index 000000000..767b08878 --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_off.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_volume_up.xml b/app/src/main/res/drawable/ic_volume_up.xml new file mode 100644 index 000000000..cdd4aac9e --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_up.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/vertical_progressbar.xml b/app/src/main/res/drawable/vertical_progressbar.xml new file mode 100644 index 000000000..c4350b1f8 --- /dev/null +++ b/app/src/main/res/drawable/vertical_progressbar.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_offline_player.xml b/app/src/main/res/layout/activity_offline_player.xml index f7c5345ec..963c69bf7 100644 --- a/app/src/main/res/layout/activity_offline_player.xml +++ b/app/src/main/res/layout/activity_offline_player.xml @@ -19,6 +19,13 @@ android:layout_gravity="center" android:gravity="center" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_player.xml b/app/src/main/res/layout/fragment_player.xml index 775e8af8c..3c2db25e5 100644 --- a/app/src/main/res/layout/fragment_player.xml +++ b/app/src/main/res/layout/fragment_player.xml @@ -397,6 +397,13 @@ android:layout_gravity="center" android:gravity="center" /> + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 771ca0c8c..55d17262c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -389,6 +389,11 @@ Local playlists Menu item not enabled! Please select an other start tab first! + Brightness + Volume + Auto + Swipe controls + Use swipe gesture to adjust the brightness and volume. Download Service diff --git a/app/src/main/res/values/style.xml b/app/src/main/res/values/style.xml index c4c8be643..72cbd129c 100644 --- a/app/src/main/res/values/style.xml +++ b/app/src/main/res/values/style.xml @@ -149,6 +149,18 @@ @android:color/white + +