Media playlist

This commit is contained in:
Matéo Duparc 2021-03-17 21:11:14 +01:00
parent e92804ae34
commit 86e9572431
Signed by untrusted user: hardcoresushi
GPG Key ID: 007F84120107191E
14 changed files with 160 additions and 200 deletions

View File

@ -15,8 +15,8 @@ android {
applicationId "sushi.hardcore.droidfs" applicationId "sushi.hardcore.droidfs"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode 11 versionCode 12
versionName "1.4.3" versionName "1.4.4"
ndk { ndk {
abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a' abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a'
@ -54,10 +54,12 @@ dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "com.jaredrummler:cyanea:1.0.2" implementation "com.jaredrummler:cyanea:1.0.2"
implementation "com.github.bumptech.glide:glide:4.11.0" implementation "com.github.bumptech.glide:glide:4.11.0"
implementation "com.google.android.exoplayer:exoplayer-core:2.11.7"
implementation "com.google.android.exoplayer:exoplayer-ui:2.11.7"
implementation "androidx.biometric:biometric:1.1.0" implementation "androidx.biometric:biometric:1.1.0"
def exoplayer_version = "2.13.2"
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version"
def camerax_version = "1.1.0-alpha01" def camerax_version = "1.1.0-alpha01"
implementation "androidx.camera:camera-camera2:$camerax_version" implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version" implementation "androidx.camera:camera-lifecycle:$camerax_version"

View File

@ -21,7 +21,7 @@ class ConstValues {
Pair("text", listOf("txt", "json", "conf", "log", "xml", "java", "kt", "py", "pl", "rb", "go", "c", "h", "cpp", "hpp", "sh", "bat", "js", "html", "css", "php", "yml", "yaml", "ini", "md")) Pair("text", listOf("txt", "json", "conf", "log", "xml", "java", "kt", "py", "pl", "rb", "go", "c", "h", "cpp", "hpp", "sh", "bat", "js", "html", "css", "php", "yml", "yaml", "ini", "md"))
) )
private fun isExtensionType(extensionType: String, path: String): Boolean { fun isExtensionType(extensionType: String, path: String): Boolean {
return fileExtensions[extensionType]?.contains(File(path).extension.toLowerCase(Locale.ROOT)) ?: false return fileExtensions[extensionType]?.contains(File(path).extension.toLowerCase(Locale.ROOT)) ?: false
} }

View File

@ -112,12 +112,11 @@ open class BaseExplorerActivity : BaseActivity() {
} }
} }
private fun startFileViewer(cls: Class<*>, filePath: String, sortOrder: String = ""){ private fun startFileViewer(cls: Class<*>, filePath: String){
val intent = Intent(this, cls) val intent = Intent(this, cls).apply {
intent.putExtra("path", filePath) putExtra("path", filePath)
intent.putExtra("sessionID", gocryptfsVolume.sessionID) putExtra("sessionID", gocryptfsVolume.sessionID)
if (sortOrder.isNotEmpty()){ putExtra("sortOrder", sortOrderValues[currentSortOrderIndex])
intent.putExtra("sortOrder", sortOrder)
} }
isStartingActivity = true isStartingActivity = true
startActivity(intent) startActivity(intent)
@ -142,7 +141,7 @@ open class BaseExplorerActivity : BaseActivity() {
setCurrentPath(PathUtils.getParentPath(currentDirectoryPath)) setCurrentPath(PathUtils.getParentPath(currentDirectoryPath))
} }
isImage(fullPath) -> { isImage(fullPath) -> {
startFileViewer(ImageViewer::class.java, fullPath, sortOrderValues[currentSortOrderIndex]) startFileViewer(ImageViewer::class.java, fullPath)
} }
isVideo(fullPath) -> { isVideo(fullPath) -> {
startFileViewer(VideoPlayer::class.java, fullPath) startFileViewer(VideoPlayer::class.java, fullPath)

View File

@ -9,6 +9,22 @@ class AudioPlayer: MediaPlayer(){
override fun viewFile() { override fun viewFile() {
setContentView(R.layout.activity_audio_player) setContentView(R.layout.activity_audio_player)
super.viewFile() super.viewFile()
refreshFileName()
}
override fun getFileType(): String {
return "audio"
}
override fun bindPlayer(player: SimpleExoPlayer) {
audio_controller.player = player
}
override fun onPlaylistIndexChanged() {
refreshFileName()
}
private fun refreshFileName() {
val filename = File(filePath).name val filename = File(filePath).name
val pos = filename.lastIndexOf('.') val pos = filename.lastIndexOf('.')
music_title.text = if (pos != -1){ music_title.text = if (pos != -1){
@ -17,8 +33,4 @@ class AudioPlayer: MediaPlayer(){
filename filename
} }
} }
override fun bindPlayer(player: SimpleExoPlayer) {
audio_controller.player = player
}
} }

View File

@ -3,16 +3,23 @@ package sushi.hardcore.droidfs.file_viewers
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import sushi.hardcore.droidfs.BaseActivity import sushi.hardcore.droidfs.BaseActivity
import sushi.hardcore.droidfs.ConstValues
import sushi.hardcore.droidfs.GocryptfsVolume
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
import sushi.hardcore.droidfs.GocryptfsVolume import sushi.hardcore.droidfs.explorers.ExplorerElement
import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
abstract class FileViewerActivity: BaseActivity() { abstract class FileViewerActivity: BaseActivity() {
lateinit var gocryptfsVolume: GocryptfsVolume protected lateinit var gocryptfsVolume: GocryptfsVolume
lateinit var filePath: String protected lateinit var filePath: String
private var isFinishingIntentionally = false private var isFinishingIntentionally = false
private var usf_keep_open = false private var usf_keep_open = false
private var wasMapped = false
protected val mappedPlaylist = mutableListOf<ExplorerElement>()
protected var currentPlaylistIndex = -1
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
filePath = intent.getStringExtra("path")!! filePath = intent.getStringExtra("path")!!
@ -22,6 +29,7 @@ abstract class FileViewerActivity: BaseActivity() {
hideSystemUi() hideSystemUi()
viewFile() viewFile()
} }
open fun hideSystemUi(){ open fun hideSystemUi(){
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_FULLSCREEN/* or View.SYSTEM_UI_FLAG_FULLSCREEN/* or
@ -31,14 +39,18 @@ abstract class FileViewerActivity: BaseActivity() {
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION*/ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION*/
} }
abstract fun getFileType(): String
abstract fun viewFile() abstract fun viewFile()
override fun onUserInteraction() { override fun onUserInteraction() {
super.onUserInteraction() super.onUserInteraction()
if (window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0){ if (window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0){
hideSystemUi() hideSystemUi()
} }
} }
fun loadWholeFile(path: String): ByteArray? {
protected fun loadWholeFile(path: String): ByteArray? {
val fileSize = gocryptfsVolume.getSize(path) val fileSize = gocryptfsVolume.getSize(path)
if (fileSize >= 0){ if (fileSize >= 0){
try { try {
@ -86,6 +98,48 @@ abstract class FileViewerActivity: BaseActivity() {
return null return null
} }
protected fun createPlaylist() {
if (!wasMapped){
for (e in gocryptfsVolume.recursiveMapFiles(PathUtils.getParentPath(filePath))){
if (e.isRegularFile) {
if (ConstValues.isExtensionType(getFileType(), e.name) || filePath == e.fullPath) {
mappedPlaylist.add(e)
}
}
}
val sortOrder = intent.getStringExtra("sortOrder") ?: "name"
ExplorerElement.sortBy(sortOrder, mappedPlaylist)
//find current index
for ((i, e) in mappedPlaylist.withIndex()){
if (filePath == e.fullPath){
currentPlaylistIndex = i
break
}
}
wasMapped = true
}
}
protected fun playlistNext(forward: Boolean) {
createPlaylist()
currentPlaylistIndex = if (forward) {
(currentPlaylistIndex+1)%mappedPlaylist.size
} else {
var x = (currentPlaylistIndex-1)%mappedPlaylist.size
if (x < 0) {
x += mappedPlaylist.size
}
x
}
filePath = mappedPlaylist[currentPlaylistIndex].fullPath
}
protected fun refreshPlaylist() {
mappedPlaylist.clear()
wasMapped = false
createPlaylist()
}
protected fun goBackToExplorer() { protected fun goBackToExplorer() {
isFinishingIntentionally = true isFinishingIntentionally = true
finish() finish()

View File

@ -1,7 +1,9 @@
package sushi.hardcore.droidfs.file_viewers package sushi.hardcore.droidfs.file_viewers
import android.net.Uri import android.net.Uri
import com.google.android.exoplayer2.upstream.* import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DataSpec
import com.google.android.exoplayer2.upstream.TransferListener
import sushi.hardcore.droidfs.ConstValues import sushi.hardcore.droidfs.ConstValues
import sushi.hardcore.droidfs.GocryptfsVolume import sushi.hardcore.droidfs.GocryptfsVolume
import kotlin.math.ceil import kotlin.math.ceil
@ -11,10 +13,8 @@ class GocryptfsDataSource(private val gocryptfsVolume: GocryptfsVolume, private
private var handleID = -1 private var handleID = -1
private var fileSize: Long = -1 private var fileSize: Long = -1
private var fileOffset: Long = 0 private var fileOffset: Long = 0
override fun open(dataSpec: DataSpec?): Long { override fun open(dataSpec: DataSpec): Long {
dataSpec?.let {
fileOffset = dataSpec.position fileOffset = dataSpec.position
}
handleID = gocryptfsVolume.openReadMode(filePath) handleID = gocryptfsVolume.openReadMode(filePath)
fileSize = gocryptfsVolume.getSize(filePath) fileSize = gocryptfsVolume.getSize(filePath)
return fileSize return fileSize
@ -28,7 +28,7 @@ class GocryptfsDataSource(private val gocryptfsVolume: GocryptfsVolume, private
gocryptfsVolume.closeFile(handleID) gocryptfsVolume.closeFile(handleID)
} }
override fun addTransferListener(transferListener: TransferListener?) { override fun addTransferListener(transferListener: TransferListener) {
//too lazy to implement this //too lazy to implement this
} }

View File

@ -16,9 +16,6 @@ import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
import kotlinx.android.synthetic.main.activity_image_viewer.* import kotlinx.android.synthetic.main.activity_image_viewer.*
import sushi.hardcore.droidfs.ConstValues import sushi.hardcore.droidfs.ConstValues
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.explorers.ExplorerElement
import sushi.hardcore.droidfs.util.MiscUtils
import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import sushi.hardcore.droidfs.widgets.ZoomableImageView import sushi.hardcore.droidfs.widgets.ZoomableImageView
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@ -36,11 +33,7 @@ class ImageViewer: FileViewerActivity() {
private lateinit var glideImage: RequestBuilder<Drawable> private lateinit var glideImage: RequestBuilder<Drawable>
private var x1 = 0F private var x1 = 0F
private var x2 = 0F private var x2 = 0F
private val mappedImages = mutableListOf<ExplorerElement>()
private lateinit var sortOrder: String
private var wasMapped = false
private var slideshowActive = false private var slideshowActive = false
private var currentMappedImageIndex = -1
private var rotationAngle: Float = 0F private var rotationAngle: Float = 0F
private var rotatedBitmap: Bitmap? = null private var rotatedBitmap: Bitmap? = null
private val handler = Handler() private val handler = Handler()
@ -54,6 +47,11 @@ class ImageViewer: FileViewerActivity() {
swipeImage(-1F, true) swipeImage(-1F, true)
} }
} }
override fun getFileType(): String {
return "image"
}
override fun viewFile() { override fun viewFile() {
setContentView(R.layout.activity_image_viewer) setContentView(R.layout.activity_image_viewer)
image_viewer.setOnInteractionListener(object : ZoomableImageView.OnInteractionListener { image_viewer.setOnInteractionListener(object : ZoomableImageView.OnInteractionListener {
@ -106,31 +104,7 @@ class ImageViewer: FileViewerActivity() {
} }
private fun swipeImage(deltaX: Float, slideshowSwipe: Boolean = false){ private fun swipeImage(deltaX: Float, slideshowSwipe: Boolean = false){
if (!wasMapped){ playlistNext(deltaX < 0)
for (e in gocryptfsVolume.recursiveMapFiles(PathUtils.getParentPath(filePath))){
if (e.isRegularFile && ConstValues.isImage(e.name)){
mappedImages.add(e)
}
}
sortOrder = intent.getStringExtra("sortOrder") ?: "name"
ExplorerElement.sortBy(sortOrder, mappedImages)
for ((i, e) in mappedImages.withIndex()){
if (filePath == e.fullPath){
currentMappedImageIndex = i
break
}
}
wasMapped = true
}
if (mappedImages.size == 0){ //can happen on deleting images
goBackToExplorer()
} else {
currentMappedImageIndex = if (deltaX < 0){
MiscUtils.incrementIndex(currentMappedImageIndex, mappedImages)
} else {
MiscUtils.decrementIndex(currentMappedImageIndex, mappedImages)
}
filePath = mappedImages[currentMappedImageIndex].fullPath
loadImage() loadImage()
if (slideshowActive){ if (slideshowActive){
if (!slideshowSwipe) { //reset slideshow delay if user swipes if (!slideshowSwipe) { //reset slideshow delay if user swipes
@ -139,7 +113,6 @@ class ImageViewer: FileViewerActivity() {
handler.postDelayed(slideshowNext, ConstValues.slideshow_delay) handler.postDelayed(slideshowNext, ConstValues.slideshow_delay)
} }
} }
}
fun onClickDelete(view: View) { fun onClickDelete(view: View) {
ColoredAlertDialogBuilder(this) ColoredAlertDialogBuilder(this)
@ -147,10 +120,13 @@ class ImageViewer: FileViewerActivity() {
.setTitle(R.string.warning) .setTitle(R.string.warning)
.setPositiveButton(R.string.ok) { _, _ -> .setPositiveButton(R.string.ok) { _, _ ->
if (gocryptfsVolume.removeFile(filePath)){ if (gocryptfsVolume.removeFile(filePath)){
currentMappedImageIndex = MiscUtils.decrementIndex(currentMappedImageIndex, mappedImages) playlistNext(true)
mappedImages.clear() refreshPlaylist()
wasMapped = false if (mappedPlaylist.size == 0) { //deleted all images of the playlist
swipeImage(-1F) goBackToExplorer()
} else {
loadImage()
}
} else { } else {
ColoredAlertDialogBuilder(this) ColoredAlertDialogBuilder(this)
.keepFullScreen() .keepFullScreen()

View File

@ -1,18 +1,17 @@
package sushi.hardcore.droidfs.file_viewers package sushi.hardcore.droidfs.file_viewers
import android.view.WindowManager import android.view.WindowManager
import androidx.appcompat.app.AlertDialog
import com.google.android.exoplayer2.ExoPlaybackException import com.google.android.exoplayer2.ExoPlaybackException
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.extractor.ExtractorsFactory
import com.google.android.exoplayer2.extractor.flac.FlacExtractor import com.google.android.exoplayer2.extractor.flac.FlacExtractor
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor
import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor
import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor
import com.google.android.exoplayer2.extractor.ogg.OggExtractor import com.google.android.exoplayer2.extractor.ogg.OggExtractor
import com.google.android.exoplayer2.extractor.wav.WavExtractor import com.google.android.exoplayer2.extractor.wav.WavExtractor
import com.google.android.exoplayer2.source.LoopingMediaSource import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.android.exoplayer2.source.ProgressiveMediaSource
import sushi.hardcore.droidfs.ConstValues import sushi.hardcore.droidfs.ConstValues
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
@ -20,46 +19,48 @@ import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
abstract class MediaPlayer: FileViewerActivity() { abstract class MediaPlayer: FileViewerActivity() {
private lateinit var player: SimpleExoPlayer private lateinit var player: SimpleExoPlayer
private var currentWindow = 0
private var playbackPosition: Long = 0
private lateinit var errorDialog: AlertDialog
override fun viewFile() { override fun viewFile() {
errorDialog = ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(R.string.playing_failed)
.setCancelable(false)
.setPositiveButton(R.string.ok) { _, _ -> goBackToExplorer()}
.create()
hideSystemUi() hideSystemUi()
initializePlayer() initializePlayer()
} }
abstract fun bindPlayer(player: SimpleExoPlayer) abstract fun bindPlayer(player: SimpleExoPlayer)
protected open fun onPlaylistIndexChanged() {}
private fun initializePlayer(){ private fun createMediaSource(filePath: String): MediaSource {
player = SimpleExoPlayer.Builder(this).build()
bindPlayer(player)
val dataSourceFactory = GocryptfsDataSource.Factory(gocryptfsVolume, filePath) val dataSourceFactory = GocryptfsDataSource.Factory(gocryptfsVolume, filePath)
val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory, ExtractorsFactory { return ProgressiveMediaSource.Factory(dataSourceFactory, { arrayOf(
arrayOf(
MatroskaExtractor(), MatroskaExtractor(),
Mp4Extractor(), Mp4Extractor(),
Mp3Extractor(), Mp3Extractor(),
OggExtractor(), OggExtractor(),
WavExtractor(), WavExtractor(),
FlacExtractor() FlacExtractor()
) ) }).createMediaSource(MediaItem.fromUri(ConstValues.fakeUri))
}).createMediaSource(ConstValues.fakeUri) }
player.seekTo(currentWindow, playbackPosition)
private fun initializePlayer(){
player = SimpleExoPlayer.Builder(this).build()
bindPlayer(player)
createPlaylist()
for (e in mappedPlaylist) {
player.addMediaSource(createMediaSource(e.fullPath))
}
player.repeatMode = Player.REPEAT_MODE_ALL
player.seekToDefaultPosition(currentPlaylistIndex)
player.playWhenReady = true player.playWhenReady = true
player.addListener(object : Player.EventListener{ player.addListener(object : Player.EventListener{
override fun onPlayerError(error: ExoPlaybackException) { override fun onPlayerError(error: ExoPlaybackException) {
if (error.type == ExoPlaybackException.TYPE_SOURCE){ if (error.type == ExoPlaybackException.TYPE_SOURCE){
errorDialog.show() ColoredAlertDialogBuilder(this@MediaPlayer)
.setTitle(R.string.error)
.setMessage(R.string.playing_failed)
.setCancelable(false)
.setPositiveButton(R.string.ok) { _, _ -> goBackToExplorer()}
.show()
} }
} }
override fun onIsPlayingChanged(isPlaying: Boolean) { override fun onIsPlayingChanged(isPlaying: Boolean) {
if (isPlaying){ if (isPlaying){
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
@ -67,20 +68,20 @@ abstract class MediaPlayer: FileViewerActivity() {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} }
} }
override fun onPositionDiscontinuity(reason: Int) {
if (player.currentWindowIndex != currentPlaylistIndex) {
playlistNext(player.currentWindowIndex == (currentPlaylistIndex+1)%mappedPlaylist.size)
onPlaylistIndexChanged()
}
}
}) })
player.prepare(LoopingMediaSource(mediaSource), false, false) player.prepare()
}
private fun releasePlayer(){
if (::player.isInitialized) {
playbackPosition = player.currentPosition
currentWindow = player.currentWindowIndex
player.release()
}
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
releasePlayer() if (::player.isInitialized) {
player.release()
}
} }
} }

View File

@ -1,5 +1,6 @@
package sushi.hardcore.droidfs.file_viewers package sushi.hardcore.droidfs.file_viewers
import android.annotation.SuppressLint
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.Menu import android.view.Menu
@ -24,6 +25,11 @@ class TextEditor: FileViewerActivity() {
override fun hideSystemUi() { override fun hideSystemUi() {
//don't hide system ui //don't hide system ui
} }
override fun getFileType(): String {
return "text"
}
override fun viewFile() { override fun viewFile() {
loadWholeFile(filePath)?.let { loadWholeFile(filePath)?.let {
fileName = File(filePath).name fileName = File(filePath).name
@ -60,6 +66,7 @@ class TextEditor: FileViewerActivity() {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (!changedSinceLastSave){ if (!changedSinceLastSave){
changedSinceLastSave = true changedSinceLastSave = true
@SuppressLint("SetTextI18n")
titleText.text = "*$fileName" titleText.text = "*$fileName"
} }
} }

View File

@ -13,4 +13,8 @@ class VideoPlayer: MediaPlayer() {
override fun bindPlayer(player: SimpleExoPlayer) { override fun bindPlayer(player: SimpleExoPlayer) {
video_player.player = player video_player.player = player
} }
override fun getFileType(): String {
return "video"
}
} }

View File

@ -1,18 +0,0 @@
package sushi.hardcore.droidfs.util
object MiscUtils {
fun incrementIndex(index: Int, list: List<Any>): Int {
var i = index+1
if (i >= list.size){
i = 0
}
return i
}
fun decrementIndex(index: Int, list: List<Any>): Int {
var i = index-1
if (i < 0){
i = list.size-1
}
return i
}
}

View File

@ -19,7 +19,6 @@
android:id="@+id/audio_controller" android:id="@+id/audio_controller"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:controller_layout_id="@layout/exo_custom_playback_control"
app:show_timeout="0"/> app:show_timeout="0"/>
</LinearLayout> </LinearLayout>

View File

@ -2,15 +2,13 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center" android:gravity="center"
android:background="@color/fullScreenBackgroundColor"> android:background="@color/fullScreenBackgroundColor">
<com.google.android.exoplayer2.ui.SimpleExoPlayerView <com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/video_player" android:id="@+id/video_player"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center" android:layout_gravity="center"/>
app:controller_layout_id="@layout/exo_custom_playback_control"/>
</LinearLayout> </LinearLayout>

View File

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layoutDirection="ltr"
android:background="#CC000000"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="4dp"
android:orientation="horizontal">
<ImageButton android:id="@id/exo_rew"
style="@style/ExoMediaButton.Rewind"/>
<ImageButton android:id="@id/exo_shuffle"
style="@style/ExoMediaButton"/>
<ImageButton android:id="@id/exo_repeat_toggle"
style="@style/ExoMediaButton"/>
<ImageButton android:id="@id/exo_play"
style="@style/ExoMediaButton.Play"/>
<ImageButton android:id="@id/exo_pause"
style="@style/ExoMediaButton.Pause"/>
<ImageButton android:id="@id/exo_ffwd"
style="@style/ExoMediaButton.FastForward"/>
<ImageButton android:id="@id/exo_vr"
style="@style/ExoMediaButton.VR"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView android:id="@id/exo_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textStyle="bold"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:includeFontPadding="false"
android:textColor="#FFBEBEBE"/>
<View android:id="@id/exo_progress_placeholder"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="26dp"/>
<TextView android:id="@id/exo_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textStyle="bold"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:includeFontPadding="false"
android:textColor="#FFBEBEBE"/>
</LinearLayout>
</LinearLayout>