play offline file if one exists and other download-related updates
|
@ -8,7 +8,7 @@ buildscript {
|
||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.0.0'
|
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
package de.nicidienase.chaosflix.touch
|
||||||
|
|
||||||
|
import android.app.DownloadManager
|
||||||
|
import android.arch.lifecycle.LiveData
|
||||||
|
import android.arch.lifecycle.MutableLiveData
|
||||||
|
import android.arch.lifecycle.Observer
|
||||||
|
import android.content.Context
|
||||||
|
import android.databinding.ObservableField
|
||||||
|
import de.nicidienase.chaosflix.common.entities.download.OfflineEvent
|
||||||
|
import io.reactivex.Completable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class OfflineItemManager(downloadRefs: List<Long>?) {
|
||||||
|
|
||||||
|
val downloadStatus: MutableMap<Long, DownloadStatus>
|
||||||
|
|
||||||
|
val downloadManager: DownloadManager
|
||||||
|
= ChaosflixApplication.APPLICATION_CONTEXT
|
||||||
|
.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
|
||||||
|
init {
|
||||||
|
downloadStatus = HashMap()
|
||||||
|
downloadRefs?.map { downloadStatus.put(it, DownloadStatus()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateDownloadStatus(offlineEvents: LiveData<List<OfflineEvent>>) {
|
||||||
|
Completable.fromAction {
|
||||||
|
offlineEvents.observeForever(Observer {
|
||||||
|
if (it != null && it.size > 0) {
|
||||||
|
val downloadRef = it.map { it.downloadReference }.toTypedArray().toLongArray() ?: longArrayOf()
|
||||||
|
val cursor = downloadManager.query(DownloadManager.Query().setFilterById(*downloadRef))
|
||||||
|
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
do {
|
||||||
|
val columnId = cursor.getColumnIndex(DownloadManager.COLUMN_ID)
|
||||||
|
val id = cursor.getLong(columnId)
|
||||||
|
val columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
|
||||||
|
val status = cursor.getInt(columnIndex)
|
||||||
|
val bytesSoFarIndex = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)
|
||||||
|
val bytesSoFar = cursor.getInt(bytesSoFarIndex)
|
||||||
|
val bytesTotalIndex = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)
|
||||||
|
val bytesTotal = cursor.getInt(bytesTotalIndex)
|
||||||
|
|
||||||
|
val statusText: String =
|
||||||
|
when (status) {
|
||||||
|
DownloadManager.STATUS_RUNNING -> "Running"
|
||||||
|
DownloadManager.STATUS_FAILED -> "Failed"
|
||||||
|
DownloadManager.STATUS_PAUSED -> "Paused"
|
||||||
|
DownloadManager.STATUS_SUCCESSFUL -> "Successful"
|
||||||
|
DownloadManager.STATUS_PENDING -> "Pending"
|
||||||
|
else -> "UNKNOWN"
|
||||||
|
}
|
||||||
|
if (downloadStatus.containsKey(id)) {
|
||||||
|
val item = downloadStatus[id]
|
||||||
|
item?.statusText?.set(statusText)
|
||||||
|
item?.currentBytes?.set(bytesSoFar)
|
||||||
|
item?.totalBytes?.set(bytesTotal)
|
||||||
|
} else {
|
||||||
|
downloadStatus.put(id, DownloadStatus(statusText, bytesSoFar, bytesTotal))
|
||||||
|
}
|
||||||
|
} while (cursor.moveToNext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}.subscribeOn(Schedulers.io()).subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteOfflineItem(item: OfflineEvent): LiveData<Boolean> {
|
||||||
|
val result = MutableLiveData<Boolean>()
|
||||||
|
Completable.fromAction {
|
||||||
|
val file = File(item.localPath)
|
||||||
|
if (file.exists()) file.delete()
|
||||||
|
result.postValue(true)
|
||||||
|
}.subscribeOn(Schedulers.io()).subscribe()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class DownloadStatus(status: String = "", currentBytes: Int = 0, totalBytes: Int = 0) {
|
||||||
|
val statusText: ObservableField<String> = ObservableField()
|
||||||
|
val currentBytes: ObservableField<Int> = ObservableField()
|
||||||
|
val totalBytes: ObservableField<Int> = ObservableField()
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.statusText.set(status)
|
||||||
|
this.currentBytes.set(currentBytes)
|
||||||
|
this.totalBytes.set(totalBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,13 @@
|
||||||
package de.nicidienase.chaosflix.touch.browse
|
package de.nicidienase.chaosflix.touch.browse
|
||||||
|
|
||||||
import android.app.DownloadManager
|
|
||||||
import android.arch.lifecycle.LiveData
|
import android.arch.lifecycle.LiveData
|
||||||
import android.arch.lifecycle.Observer
|
import android.arch.lifecycle.Observer
|
||||||
import android.arch.lifecycle.ViewModel
|
import android.arch.lifecycle.ViewModel
|
||||||
import android.content.Context
|
|
||||||
import android.databinding.ObservableField
|
|
||||||
import android.os.Environment
|
|
||||||
import de.nicidienase.chaosflix.common.entities.ChaosflixDatabase
|
import de.nicidienase.chaosflix.common.entities.ChaosflixDatabase
|
||||||
import de.nicidienase.chaosflix.common.entities.download.OfflineEvent
|
import de.nicidienase.chaosflix.common.entities.download.OfflineEvent
|
||||||
import de.nicidienase.chaosflix.common.network.RecordingService
|
import de.nicidienase.chaosflix.common.network.RecordingService
|
||||||
import de.nicidienase.chaosflix.common.network.StreamingService
|
import de.nicidienase.chaosflix.common.network.StreamingService
|
||||||
import de.nicidienase.chaosflix.touch.ChaosflixApplication
|
import de.nicidienase.chaosflix.touch.OfflineItemManager
|
||||||
import de.nicidienase.chaosflix.touch.sync.Downloader
|
import de.nicidienase.chaosflix.touch.sync.Downloader
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
@ -24,12 +20,14 @@ class BrowseViewModel(
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
val downloader = Downloader(recordingApi, database)
|
val downloader = Downloader(recordingApi, database)
|
||||||
|
lateinit var offlineItemManager: OfflineItemManager
|
||||||
|
|
||||||
val downloadManager: DownloadManager
|
init {
|
||||||
= ChaosflixApplication.APPLICATION_CONTEXT
|
getOfflineEvents().observeForever(Observer {
|
||||||
.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
val downloadRefs = it?.map { it.downloadReference } ?: emptyList()
|
||||||
|
offlineItemManager = OfflineItemManager(downloadRefs)
|
||||||
val downloadStatus: MutableMap<Long, DownloadStatus> = HashMap()
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fun getConferenceGroups()
|
fun getConferenceGroups()
|
||||||
= database.conferenceGroupDao().getAll()
|
= database.conferenceGroupDao().getAll()
|
||||||
|
@ -64,77 +62,13 @@ class BrowseViewModel(
|
||||||
|
|
||||||
fun getRecordingByid(recordingId: Long) = database.recordingDao().findRecordingById(recordingId)
|
fun getRecordingByid(recordingId: Long) = database.recordingDao().findRecordingById(recordingId)
|
||||||
|
|
||||||
init {
|
|
||||||
getOfflineEvents().observeForever(Observer {
|
|
||||||
val downloadRef = it?.map { it.downloadReference }?.map { downloadStatus.put(it, DownloadStatus()) }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateDownloadStatus() {
|
fun updateDownloadStatus() {
|
||||||
Completable.fromAction {
|
offlineItemManager.updateDownloadStatus(getOfflineEvents())
|
||||||
getOfflineEvents().observeForever(Observer {
|
|
||||||
if (it != null && it.size > 0) {
|
|
||||||
val downloadRef = it.map { it.downloadReference }.toTypedArray().toLongArray() ?: longArrayOf()
|
|
||||||
val cursor = downloadManager.query(DownloadManager.Query().setFilterById(*downloadRef))
|
|
||||||
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
do {
|
|
||||||
val columnId = cursor.getColumnIndex(DownloadManager.COLUMN_ID)
|
|
||||||
val id = cursor.getLong(columnId)
|
|
||||||
val columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
|
|
||||||
val status = cursor.getInt(columnIndex)
|
|
||||||
val bytesSoFarIndex = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)
|
|
||||||
val bytesSoFar = cursor.getInt(bytesSoFarIndex)
|
|
||||||
val bytesTotalIndex = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)
|
|
||||||
val bytesTotal = cursor.getInt(bytesTotalIndex)
|
|
||||||
|
|
||||||
val statusText: String =
|
|
||||||
when (status) {
|
|
||||||
DownloadManager.STATUS_RUNNING -> "Running"
|
|
||||||
DownloadManager.STATUS_FAILED -> "Failed"
|
|
||||||
DownloadManager.STATUS_PAUSED -> "Paused"
|
|
||||||
DownloadManager.STATUS_SUCCESSFUL -> "Successful"
|
|
||||||
DownloadManager.STATUS_PENDING -> "Pending"
|
|
||||||
else -> "UNKNOWN"
|
|
||||||
}
|
|
||||||
if (downloadStatus.containsKey(id)) {
|
|
||||||
val item = downloadStatus[id]
|
|
||||||
item?.statusText?.set(statusText)
|
|
||||||
item?.currentBytes?.set(bytesSoFar)
|
|
||||||
item?.totalBytes?.set(bytesTotal)
|
|
||||||
} else {
|
|
||||||
downloadStatus.put(id, DownloadStatus(statusText, bytesSoFar, bytesTotal))
|
|
||||||
}
|
|
||||||
} while (cursor.moveToNext())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}.subscribeOn(Schedulers.io()).subscribe()
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class DownloadStatus(status: String = "", currentBytes: Int = 0, totalBytes: Int = 0) {
|
|
||||||
val statusText: ObservableField<String> = ObservableField()
|
|
||||||
val currentBytes: ObservableField<Int> = ObservableField()
|
|
||||||
val totalBytes: ObservableField<Int> = ObservableField()
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.statusText.set(status)
|
|
||||||
this.currentBytes.set(currentBytes)
|
|
||||||
this.totalBytes.set(totalBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getUriForEvent(item: OfflineEvent): String {
|
|
||||||
val directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
|
|
||||||
val uri = "${directory.toURI()}chaosflix/${item.localPath}"
|
|
||||||
return uri
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteOfflineItem(item: OfflineEvent) {
|
fun deleteOfflineItem(item: OfflineEvent) {
|
||||||
Completable.fromAction {
|
Completable.fromAction {
|
||||||
val directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
|
val file = File(item.localPath)
|
||||||
val file = File("${directory.path}/chaosflix/${item.localPath}")
|
|
||||||
if (file.exists()) file.delete()
|
if (file.exists()) file.delete()
|
||||||
database.offlineEventDao().deleteById(item.id)
|
database.offlineEventDao().deleteById(item.id)
|
||||||
}.subscribeOn(Schedulers.io()).subscribe()
|
}.subscribeOn(Schedulers.io()).subscribe()
|
||||||
|
|
|
@ -57,6 +57,6 @@ open class EventRecyclerViewAdapter(val listener: OnEventSelectedListener) :
|
||||||
ViewCompat.setTransitionName(holder.mIcon,
|
ViewCompat.setTransitionName(holder.mIcon,
|
||||||
resources.getString(R.string.thumbnail) + event.eventId)
|
resources.getString(R.string.thumbnail) + event.eventId)
|
||||||
|
|
||||||
holder.mView.setOnClickListener({ v: View -> listener.onEventSelected(items[position]) })
|
holder.mView.setOnClickListener({ _: View -> listener.onEventSelected(items[position]) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
package de.nicidienase.chaosflix.touch.browse.download
|
package de.nicidienase.chaosflix.touch.browse.download
|
||||||
|
|
||||||
import android.arch.lifecycle.Observer
|
|
||||||
import android.databinding.DataBindingUtil
|
import android.databinding.DataBindingUtil
|
||||||
import android.os.Environment
|
|
||||||
import android.support.design.widget.Snackbar
|
|
||||||
import android.support.v7.widget.PopupMenu
|
|
||||||
import android.support.v7.widget.RecyclerView
|
import android.support.v7.widget.RecyclerView
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -15,7 +11,6 @@ import de.nicidienase.chaosflix.common.entities.download.OfflineEvent
|
||||||
import de.nicidienase.chaosflix.databinding.ItemOfflineEventBinding
|
import de.nicidienase.chaosflix.databinding.ItemOfflineEventBinding
|
||||||
import de.nicidienase.chaosflix.touch.OnEventSelectedListener
|
import de.nicidienase.chaosflix.touch.OnEventSelectedListener
|
||||||
import de.nicidienase.chaosflix.touch.browse.BrowseViewModel
|
import de.nicidienase.chaosflix.touch.browse.BrowseViewModel
|
||||||
import de.nicidienase.chaosflix.touch.playback.PlayerActivity
|
|
||||||
|
|
||||||
class OfflineEventAdapter(var items: List<OfflineEvent>, val viewModel: BrowseViewModel, val listener: OnEventSelectedListener) :
|
class OfflineEventAdapter(var items: List<OfflineEvent>, val viewModel: BrowseViewModel, val listener: OnEventSelectedListener) :
|
||||||
RecyclerView.Adapter<OfflineEventAdapter.ViewHolder>() {
|
RecyclerView.Adapter<OfflineEventAdapter.ViewHolder>() {
|
||||||
|
@ -37,44 +32,17 @@ class OfflineEventAdapter(var items: List<OfflineEvent>, val viewModel: BrowseVi
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
holder.binding.downloadStatus = viewModel.downloadStatus[item.downloadReference]
|
holder.binding.downloadStatus = viewModel.offlineItemManager.downloadStatus[item.downloadReference]
|
||||||
holder.binding.card.setOnClickListener { view ->
|
holder.binding.buttonDelete.setOnClickListener {
|
||||||
// item.event?.let {
|
viewModel.deleteOfflineItem(item)
|
||||||
// listener.onEventSelected(it)
|
}
|
||||||
// }
|
holder.binding.content.setOnClickListener {
|
||||||
// }
|
item.event?.let {
|
||||||
//
|
listener.onEventSelected(it)
|
||||||
// holder.binding.textViewOptions.setOnClickListener {
|
|
||||||
// holder.binding.card.setOnClickListener {
|
|
||||||
val menu = PopupMenu(holder.view.context, holder.binding.card)
|
|
||||||
menu.inflate(R.menu.offline_menu)
|
|
||||||
menu.setOnMenuItemClickListener { menuItem ->
|
|
||||||
when (menuItem.itemId) {
|
|
||||||
R.id.item_open -> {
|
|
||||||
item.event?.let {
|
|
||||||
listener.onEventSelected(it)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
R.id.item_play -> {
|
|
||||||
PlayerActivity.launch(view.context, item.event!!, viewModel.getUriForEvent(item))
|
|
||||||
true
|
|
||||||
}
|
|
||||||
R.id.item_delete -> {
|
|
||||||
viewModel.deleteOfflineItem(item)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
menu.show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return items.size
|
return items.size
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import de.nicidienase.chaosflix.touch.ChaosflixApplication
|
||||||
import de.nicidienase.chaosflix.touch.sync.Downloader
|
import de.nicidienase.chaosflix.touch.sync.Downloader
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class DetailsViewModel(
|
class DetailsViewModel(
|
||||||
val database: ChaosflixDatabase,
|
val database: ChaosflixDatabase,
|
||||||
|
@ -80,7 +81,7 @@ class DetailsViewModel(
|
||||||
Completable.fromAction {
|
Completable.fromAction {
|
||||||
database.offlineEventDao().insert(
|
database.offlineEventDao().insert(
|
||||||
OfflineEvent(eventId = event.eventId, recordingId = recording.recordingId,
|
OfflineEvent(eventId = event.eventId, recordingId = recording.recordingId,
|
||||||
localPath = recording.filename, downloadReference = downloadReference))
|
localPath = getDownloadDir() + recording.filename, downloadReference = downloadReference))
|
||||||
result.postValue(true)
|
result.postValue(true)
|
||||||
}.subscribeOn(Schedulers.io()).subscribe()
|
}.subscribeOn(Schedulers.io()).subscribe()
|
||||||
} else {
|
} else {
|
||||||
|
@ -90,8 +91,30 @@ class DetailsViewModel(
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getOfflineItem(eventId: Long) = database.offlineEventDao().getByEventId(eventId)
|
||||||
|
|
||||||
|
fun offlineItemExists(eventId: Long): LiveData<Boolean> {
|
||||||
|
val result = MutableLiveData<Boolean>()
|
||||||
|
getOfflineItem(eventId).observeForever({ event: OfflineEvent? ->
|
||||||
|
result.postValue(if (event != null) File(event.localPath).exists() else false)
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteOfflineItem(item: OfflineEvent) {
|
||||||
|
Completable.fromAction {
|
||||||
|
val file = File(item.localPath)
|
||||||
|
if (file.exists()) file.delete()
|
||||||
|
database.offlineEventDao().deleteById(item.id)
|
||||||
|
}.subscribeOn(Schedulers.io()).subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDownloadDir(): String {
|
||||||
|
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).path + DOWNLOAD_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val DOWNLOAD_DIR = "chaosflix/"
|
val DOWNLOAD_DIR = "/chaosflix/"
|
||||||
val TAG = DetailsViewModel::class.simpleName
|
val TAG = DetailsViewModel::class.simpleName
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,7 +19,6 @@ import de.nicidienase.chaosflix.touch.playback.PlayerActivity
|
||||||
class EventDetailsActivity : AppCompatActivity(),
|
class EventDetailsActivity : AppCompatActivity(),
|
||||||
EventDetailsFragment.OnEventDetailsFragmentInteractionListener,
|
EventDetailsFragment.OnEventDetailsFragmentInteractionListener,
|
||||||
OnEventSelectedListener {
|
OnEventSelectedListener {
|
||||||
|
|
||||||
override fun onEventSelected(event: PersistentEvent) {
|
override fun onEventSelected(event: PersistentEvent) {
|
||||||
showFragmentForEvent(event.eventId, true)
|
showFragmentForEvent(event.eventId, true)
|
||||||
}
|
}
|
||||||
|
@ -65,6 +64,10 @@ class EventDetailsActivity : AppCompatActivity(),
|
||||||
PlayerActivity.launch(this, event, recording)
|
PlayerActivity.launch(this, event, recording)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun playItem(event: PersistentEvent, uri: String) {
|
||||||
|
PlayerActivity.launch(this,event,uri)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val EXTRA_EVENT = "extra_event"
|
private val EXTRA_EVENT = "extra_event"
|
||||||
|
|
||||||
|
|
|
@ -125,16 +125,20 @@ class EventDetailsFragment : Fragment() {
|
||||||
|
|
||||||
private fun play() {
|
private fun play() {
|
||||||
listener?.let {
|
listener?.let {
|
||||||
val event = this.event
|
viewModel.getOfflineItem(eventId).observe(this, Observer { offlineEvent ->
|
||||||
if (event != null) {
|
if(offlineEvent != null){
|
||||||
|
Log.d(TAG,"Playing offline file")
|
||||||
viewModel.getRecordingForEvent(eventId)
|
listener?.playItem(event,offlineEvent.localPath)
|
||||||
.observe(this, Observer { persistentRecordings ->
|
} else {
|
||||||
if (persistentRecordings != null) {
|
viewModel.getRecordingForEvent(eventId)
|
||||||
listener!!.playItem(event, Util.getOptimalStream(persistentRecordings))
|
.observe(this, Observer { persistentRecordings ->
|
||||||
}
|
if (persistentRecordings != null) {
|
||||||
})
|
Log.d(TAG,"Playing network file")
|
||||||
}
|
listener!!.playItem(event, Util.getOptimalStream(persistentRecordings))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +170,16 @@ class EventDetailsFragment : Fragment() {
|
||||||
menu.findItem(R.id.action_unbookmark).isVisible = false
|
menu.findItem(R.id.action_unbookmark).isVisible = false
|
||||||
}
|
}
|
||||||
menu.findItem(R.id.action_download).isVisible = viewModel.writeExternalStorageAllowed
|
menu.findItem(R.id.action_download).isVisible = viewModel.writeExternalStorageAllowed
|
||||||
|
viewModel.offlineItemExists(eventId).observe(this,
|
||||||
|
Observer { itemExists ->
|
||||||
|
itemExists?.let {
|
||||||
|
menu.findItem(R.id.action_download).isVisible =
|
||||||
|
viewModel.writeExternalStorageAllowed && !itemExists
|
||||||
|
menu.findItem(R.id.action_delete_offline_item).isVisible =
|
||||||
|
viewModel.writeExternalStorageAllowed && itemExists
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
menu.findItem(R.id.action_play).isVisible = appBarExpanded
|
menu.findItem(R.id.action_play).isVisible = appBarExpanded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,12 +214,21 @@ class EventDetailsFragment : Fragment() {
|
||||||
R.id.action_download -> {
|
R.id.action_download -> {
|
||||||
viewModel.getRecordingForEvent(eventId).observeForever {
|
viewModel.getRecordingForEvent(eventId).observeForever {
|
||||||
viewModel.download(event, Util.getOptimalStream(it!!)).observe(this, Observer {
|
viewModel.download(event, Util.getOptimalStream(it!!)).observe(this, Observer {
|
||||||
if(it != null){
|
if (it != null) {
|
||||||
val message = if(it) "Download started" else "Error starting download"
|
val message = if (it) "Download started" else "Error starting download"
|
||||||
Snackbar.make(view!!,message, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(view!!, message, Snackbar.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
activity?.invalidateOptionsMenu()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_delete_offline_item -> {
|
||||||
|
viewModel.getOfflineItem(eventId).observeForever {
|
||||||
|
if (it != null) {
|
||||||
|
viewModel.deleteOfflineItem(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
else -> return super.onOptionsItemSelected(item)
|
else -> return super.onOptionsItemSelected(item)
|
||||||
|
@ -217,6 +240,7 @@ class EventDetailsFragment : Fragment() {
|
||||||
fun onToolbarStateChange()
|
fun onToolbarStateChange()
|
||||||
fun invalidateOptionsMenu()
|
fun invalidateOptionsMenu()
|
||||||
fun playItem(event: PersistentEvent, recording: PersistentRecording)
|
fun playItem(event: PersistentEvent, recording: PersistentRecording)
|
||||||
|
fun playItem(event: PersistentEvent, uri: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -20,10 +20,10 @@ class Downloader(val recordingApi: RecordingService,
|
||||||
|
|
||||||
private fun updateEverything() {
|
private fun updateEverything() {
|
||||||
updateConferencesAndGroups { conferenceIds ->
|
updateConferencesAndGroups { conferenceIds ->
|
||||||
for (id in conferenceIds) {
|
for (confId in conferenceIds) {
|
||||||
updateEventsForConference(id) { eventIds ->
|
updateEventsForConference(confId) { eventIds ->
|
||||||
for (id in eventIds) {
|
for (eventId in eventIds) {
|
||||||
updateRecordingsForEvent(id)
|
updateRecordingsForEvent(eventId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
touch/src/main/res/drawable-hdpi/ic_delete.png
Normal file
After Width: | Height: | Size: 227 B |
BIN
touch/src/main/res/drawable-hdpi/ic_delete_dark.png
Normal file
After Width: | Height: | Size: 257 B |
BIN
touch/src/main/res/drawable-mdpi/ic_delete.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
touch/src/main/res/drawable-mdpi/ic_delete_dark.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
touch/src/main/res/drawable-xhdpi/ic_delete.png
Normal file
After Width: | Height: | Size: 255 B |
BIN
touch/src/main/res/drawable-xhdpi/ic_delete_dark.png
Normal file
After Width: | Height: | Size: 279 B |
BIN
touch/src/main/res/drawable-xxhdpi/ic_delete.png
Normal file
After Width: | Height: | Size: 418 B |
BIN
touch/src/main/res/drawable-xxhdpi/ic_delete_dark.png
Normal file
After Width: | Height: | Size: 474 B |
|
@ -1,10 +1,11 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
<import type="de.nicidienase.chaosflix.touch.browse.BrowseViewModel.DownloadStatus"/>
|
<import type="de.nicidienase.chaosflix.touch.OfflineItemManager.DownloadStatus"/>
|
||||||
|
|
||||||
<import type="de.nicidienase.chaosflix.common.entities.recording.persistence.PersistentEvent"/>
|
<import type="de.nicidienase.chaosflix.common.entities.recording.persistence.PersistentEvent"/>
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@
|
||||||
android:scaleType="fitCenter"/>
|
android:scaleType="fitCenter"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
|
@ -82,11 +84,18 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:gravity="bottom|right"
|
android:gravity="bottom|right"
|
||||||
|
android:paddingRight="8dp"
|
||||||
android:text="@{downloadStatus.statusText}"
|
android:text="@{downloadStatus.statusText}"
|
||||||
tools:text="Tag"/>
|
tools:text="Tag"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/button_delete"
|
||||||
|
android:layout_width="@dimen/del_button_size"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/button_rect_normal"
|
||||||
|
app:srcCompat="@drawable/ic_delete_dark"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
|
<menu xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
|
@ -15,11 +16,17 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_unbookmark"
|
android:id="@+id/action_unbookmark"
|
||||||
android:icon="@drawable/ic_bookmark"
|
android:icon="@drawable/ic_bookmark"
|
||||||
android:title="Remove Bookmark"
|
android:title="@string/remove_bookmark"
|
||||||
app:showAsAction="ifRoom"/>
|
app:showAsAction="ifRoom"/>
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_download"
|
android:id="@+id/action_download"
|
||||||
android:title="@string/download"
|
android:title="@string/download"
|
||||||
android:icon="@drawable/ic_download"
|
android:icon="@drawable/ic_download"
|
||||||
app:showAsAction="ifRoom"/>
|
app:showAsAction="ifRoom"/>
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_delete_offline_item"
|
||||||
|
android:title="@string/delete_local_file"
|
||||||
|
android:icon="@drawable/ic_delete"
|
||||||
|
android:visible="false"
|
||||||
|
app:showAsAction="always"/>
|
||||||
</menu>
|
</menu>
|
|
@ -6,4 +6,5 @@
|
||||||
<dimen name="margin_content">120dp</dimen>
|
<dimen name="margin_content">120dp</dimen>
|
||||||
<dimen name="details_text_margin">8dp</dimen>
|
<dimen name="details_text_margin">8dp</dimen>
|
||||||
<dimen name="details_title_margin">25dp</dimen>
|
<dimen name="details_title_margin">25dp</dimen>
|
||||||
|
<dimen name="del_button_size">64dp</dimen>
|
||||||
</resources>
|
</resources>
|
|
@ -33,4 +33,6 @@
|
||||||
<string name="drawer_close">Drawer closed</string>
|
<string name="drawer_close">Drawer closed</string>
|
||||||
<string name="about_description">TODO: Description</string>
|
<string name="about_description">TODO: Description</string>
|
||||||
<string name="about_title">Chaosflix</string>
|
<string name="about_title">Chaosflix</string>
|
||||||
|
<string name="remove_bookmark">Remove Bookmark</string>
|
||||||
|
<string name="delete_local_file">Delete local File</string>
|
||||||
</resources>
|
</resources>
|