Added a progress bar to TrackDownloadActivity.

This commit is contained in:
casey langen 2019-05-02 22:15:29 -07:00
parent 058fd842b3
commit 4453935b9d
7 changed files with 109 additions and 40 deletions

View File

@ -3,6 +3,7 @@
musikcube:
* added lyrics support (powered by audd.io)! access lyrics for the currently
playing song by pressing ^L.
* removed vcredist runtime requirement on windows
musikdroid:
* added a new "offline" tab to the browse screen
@ -10,6 +11,8 @@ musikdroid:
screen's toolbar.
* added settings > advanced > diagnostics screen to show app runtime, wakelock
acquisition time and status, and service status.
* added a "download" option for song rows -- this can be used to download songs
for ringtones, or for playback in offline players.
* added the ability to seek playback on secondary screens
* removed some old settings that are no longer useful
* updated to AndroidX

2
src/3rdparty/bin vendored

@ -1 +1 @@
Subproject commit 31cd7109785075fc18ddb6319440c5cbb305e702
Subproject commit f77857c24dec5e4d6d900995ed3d140088657eb6

View File

@ -46,7 +46,7 @@
android:windowSoftInputMode="adjustResize"
android:theme="@style/AppThemeNoActionBar" />
<activity android:name=".ui.download.activity.RingtoneActivity"
<activity android:name=".ui.download.activity.TrackDownloadActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"
android:theme="@style/AppThemeNoActionBar" />

View File

@ -8,6 +8,9 @@ import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.os.Handler
import android.util.Log
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
@ -20,6 +23,7 @@ import io.casey.musikcube.remote.service.websocket.model.ITrack
import io.casey.musikcube.remote.ui.settings.constants.Prefs
import io.casey.musikcube.remote.ui.shared.activity.BaseActivity
import io.casey.musikcube.remote.ui.shared.extension.*
import me.zhanghai.android.materialprogressbar.MaterialProgressBar
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Request
@ -27,19 +31,24 @@ import okhttp3.Response
import java.io.File
import java.io.IOException
class RingtoneActivity: BaseActivity() {
class TrackDownloadActivity: BaseActivity() {
private val httpClient = createHttpClient(Application.instance)
private val mutex = Object()
private var pendingCall: Call? = null
private lateinit var spinner: MaterialProgressBar
private lateinit var progress: MaterialProgressBar
private val handler = Handler()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.download_ringtone_activity)
setContentView(R.layout.track_download_activity)
findViewById<TextView>(R.id.title).text = getString(
R.string.downloading_please_wait,
intent.getStringExtra(EXTRA_TRACK_TITLE))
progress = findViewById(R.id.progress)
spinner = findViewById(R.id.spinner)
if (savedInstanceState != null) {
findDialog<RetryDialog>(RetryDialog.TAG)?.onRetry = this::download
@ -99,6 +108,68 @@ class RingtoneActivity: BaseActivity() {
}
}
private fun updateProgress(percent: Int) {
handler.post {
if (percent > 0) {
spinner.visibility = View.GONE
progress.visibility = View.VISIBLE
progress.progress = percent
}
else {
spinner.visibility = View.VISIBLE
progress.visibility = View.GONE
}
}
}
private fun processResponse(response: Response) {
var success = false
try {
response.body()?.let {
val total = it.contentLength()
var lastPercent = 0
updateProgress(0)
val onBytesReceived = { bytes: Long ->
if (total > 0) {
val updatedPercent = ((bytes * 100) / total).toInt()
if (updatedPercent != lastPercent) {
updateProgress(updatedPercent)
lastPercent = updatedPercent
}
}
}
if (it.byteStream().toFile(outputFilename, onBytesReceived)) {
MediaScannerConnection.scanFile(
this@TrackDownloadActivity,
arrayOf(outputFilename),
null)
{ _, _ ->
finish()
}
success = true
}
}
}
catch (ex: Exception) {
/* move on... */
}
finally {
synchronized (mutex) {
pendingCall = null
}
response.close()
}
if (!success) {
showRetryDialog()
}
}
private fun download() {
synchronized (mutex) {
if (pendingCall == null) {
@ -111,34 +182,7 @@ class RingtoneActivity: BaseActivity() {
}
override fun onResponse(call: Call, response: Response) {
var success = false
try {
if (response.body()?.byteStream()?.toFile(outputFilename) == true) {
MediaScannerConnection.scanFile(
this@RingtoneActivity,
arrayOf(outputFilename),
null)
{ _, _ ->
finish()
}
success = true
}
}
catch (ex: Exception) {
/* move on... */
}
finally {
synchronized (mutex) {
pendingCall = null
}
response.close()
}
if (!success) {
showRetryDialog()
}
processResponse(response)
}
})
}
@ -154,7 +198,7 @@ class RingtoneActivity: BaseActivity() {
private fun showRetryDialog() {
if (!dialogVisible(RetryDialog.TAG)) {
showDialog(RetryDialog.create().apply {
onRetry = this@RingtoneActivity::download
onRetry = this@TrackDownloadActivity::download
}, RetryDialog.TAG)
}
}
@ -233,7 +277,7 @@ class RingtoneActivity: BaseActivity() {
private const val EXTRA_EXTENSION = "extra_extension"
fun getStartIntent(activity: AppCompatActivity, track: ITrack): Intent {
return Intent(activity, RingtoneActivity::class.java).apply {
return Intent(activity, TrackDownloadActivity::class.java).apply {
putExtra(EXTRA_EXTERNAL_ID, track.externalId)
putExtra(EXTRA_EXTENSION, track.uri.split(".").lastOrNull())
putExtra(EXTRA_TRACK_TITLE, track.title)

View File

@ -17,7 +17,7 @@ import io.casey.musikcube.remote.ui.category.activity.AllCategoriesActivity
import io.casey.musikcube.remote.ui.category.activity.CategoryBrowseActivity
import io.casey.musikcube.remote.ui.category.constant.NavigationType
import io.casey.musikcube.remote.ui.category.fragment.CategoryBrowseFragment
import io.casey.musikcube.remote.ui.download.activity.RingtoneActivity
import io.casey.musikcube.remote.ui.download.activity.TrackDownloadActivity
import io.casey.musikcube.remote.ui.home.activity.MainActivity
import io.casey.musikcube.remote.ui.playqueue.activity.PlayQueueActivity
import io.casey.musikcube.remote.ui.playqueue.fragment.PlayQueueFragment
@ -240,7 +240,7 @@ object Navigate {
*/
fun toDownloadRingtone(track: ITrack, activity: AppCompatActivity) =
activity.startActivity(RingtoneActivity.getStartIntent(activity, track))
activity.startActivity(TrackDownloadActivity.getStartIntent(activity, track))
/*
*

View File

@ -505,19 +505,27 @@ fun createHttpClient(context: Context): OkHttpClient {
*
*/
fun InputStream.toFile(path: String): Boolean {
fun InputStream.toFile(path: String, progress: ((Long) -> Unit)? = null): Boolean {
try {
File(path).parentFile.mkdirs()
File(path).delete()
FileOutputStream(path, false).use { out ->
val reader = BufferedInputStream(this)
val buffer = ByteArray(4096)
var iterations = 0
var count: Int
var total = 0L
do {
count = reader.read(buffer)
total += count
if (count > 0) {
out.write(buffer)
}
++iterations
/* post progress every ~(4096 * 25 = 102400) bytes */
if (iterations % 25 == 0) {
progress?.invoke(total)
}
} while (count > 0)
}
}

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
@ -20,9 +20,23 @@
android:text="@string/downloading_please_wait"/>
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal"
android:id="@+id/progress"
android:visibility="gone"
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="12dp"
android:indeterminate="false"
android:progress="25"
android:max="100"
app:mpb_progressStyle="horizontal"
app:mpb_useIntrinsicPadding="false" />
</LinearLayout>
</FrameLayout>