Improve updates fragment actions
This commit is contained in:
@@ -37,6 +37,10 @@ fun View.hide() {
|
|||||||
visibility = View.GONE
|
visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun View.invisible() {
|
||||||
|
visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
fun View.showKeyboard() {
|
fun View.showKeyboard() {
|
||||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
this.requestFocus()
|
this.requestFocus()
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ sealed class InstallerEvent {
|
|||||||
var extra: String? = ""
|
var extra: String? = ""
|
||||||
) : InstallerEvent()
|
) : InstallerEvent()
|
||||||
|
|
||||||
|
data class Cancelled(
|
||||||
|
var packageName: String? = "",
|
||||||
|
var extra: String? = ""
|
||||||
|
) : InstallerEvent()
|
||||||
|
|
||||||
data class Failed(
|
data class Failed(
|
||||||
var packageName: String? = "",
|
var packageName: String? = "",
|
||||||
var error: String? = "",
|
var error: String? = "",
|
||||||
|
|||||||
@@ -67,6 +67,13 @@ class InstallerService : Service() {
|
|||||||
PackageInstaller.STATUS_SUCCESS -> {
|
PackageInstaller.STATUS_SUCCESS -> {
|
||||||
EventBus.getDefault().post(InstallerEvent.Success(packageName, "Success"))
|
EventBus.getDefault().post(InstallerEvent.Success(packageName, "Success"))
|
||||||
}
|
}
|
||||||
|
PackageInstaller.STATUS_FAILURE_ABORTED -> {
|
||||||
|
val errorString = AppInstaller.getErrorString(this, status)
|
||||||
|
val event =
|
||||||
|
InstallerEvent.Cancelled(packageName, errorString)
|
||||||
|
Log.e("$packageName : $errorString")
|
||||||
|
EventBus.getDefault().post(event)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val errorString =
|
val errorString =
|
||||||
AppInstaller.getErrorString(this, status)
|
AppInstaller.getErrorString(this, status)
|
||||||
|
|||||||
@@ -77,9 +77,10 @@ class UpdateButton : RelativeLayout {
|
|||||||
|
|
||||||
fun updateState(state: State) {
|
fun updateState(state: State) {
|
||||||
val displayChild = when (state) {
|
val displayChild = when (state) {
|
||||||
State.IDLE, State.COMPLETE, State.CANCELED -> 0
|
State.IDLE, State.CANCELED -> 0
|
||||||
State.QUEUED -> 1
|
State.QUEUED -> 1
|
||||||
State.PROGRESS -> 2
|
State.PROGRESS -> 2
|
||||||
|
State.COMPLETE -> 3
|
||||||
}
|
}
|
||||||
|
|
||||||
if (B.viewFlipper.displayedChild != displayChild) {
|
if (B.viewFlipper.displayedChild != displayChild) {
|
||||||
@@ -96,4 +97,8 @@ class UpdateButton : RelativeLayout {
|
|||||||
fun addNegativeOnClickListener(onClickListener: OnClickListener?) {
|
fun addNegativeOnClickListener(onClickListener: OnClickListener?) {
|
||||||
B.btnNegative.setOnClickListener(onClickListener)
|
B.btnNegative.setOnClickListener(onClickListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addInstallOnClickListener(onClickListener: OnClickListener?) {
|
||||||
|
B.btnInstall.setOnClickListener(onClickListener)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ import com.airbnb.epoxy.CallbackProp
|
|||||||
import com.airbnb.epoxy.ModelProp
|
import com.airbnb.epoxy.ModelProp
|
||||||
import com.airbnb.epoxy.ModelView
|
import com.airbnb.epoxy.ModelView
|
||||||
import com.airbnb.epoxy.OnViewRecycled
|
import com.airbnb.epoxy.OnViewRecycled
|
||||||
import com.aurora.extensions.hide
|
import com.aurora.extensions.invisible
|
||||||
import com.aurora.extensions.load
|
import com.aurora.extensions.load
|
||||||
import com.aurora.extensions.px
|
import com.aurora.extensions.px
|
||||||
import com.aurora.extensions.show
|
import com.aurora.extensions.show
|
||||||
@@ -105,22 +105,32 @@ class AppUpdateView : RelativeLayout {
|
|||||||
|
|
||||||
/*Inflate Download details*/
|
/*Inflate Download details*/
|
||||||
updateFile.group?.let {
|
updateFile.group?.let {
|
||||||
if (updateFile.state == State.PROGRESS) {
|
when (updateFile.state) {
|
||||||
val progress = it.groupDownloadProgress
|
State.QUEUED -> {
|
||||||
if (progress > 0) {
|
B.progressDownload.progress = 0
|
||||||
if (progress == 100) {
|
B.progressDownload.show()
|
||||||
B.txtProgressPercent.hide()
|
B.btnAction.updateState(State.QUEUED)
|
||||||
} else {
|
}
|
||||||
B.txtProgressPercent.show()
|
State.IDLE, State.CANCELED -> {
|
||||||
B.txtProgressPercent.text = ("${progress}%")
|
B.progressDownload.progress = 0
|
||||||
|
B.progressDownload.invisible()
|
||||||
|
B.btnAction.updateState(State.IDLE)
|
||||||
|
}
|
||||||
|
State.PROGRESS -> {
|
||||||
|
val progress = it.groupDownloadProgress
|
||||||
|
if (progress > 0) {
|
||||||
|
if (progress == 100) {
|
||||||
|
B.progressDownload.invisible()
|
||||||
|
} else {
|
||||||
|
B.progressDownload.progress = progress
|
||||||
|
B.progressDownload.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (updateFile.state == State.IDLE || updateFile.state == State.CANCELED) {
|
State.COMPLETE -> {
|
||||||
B.btnAction.updateState(State.IDLE)
|
B.progressDownload.invisible()
|
||||||
B.txtProgressPercent.text = ("0%")
|
B.btnAction.updateState(State.COMPLETE)
|
||||||
B.txtProgressPercent.hide()
|
}
|
||||||
} else if (updateFile.state == State.QUEUED) {
|
|
||||||
B.btnAction.updateState(State.QUEUED)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,6 +158,11 @@ class AppUpdateView : RelativeLayout {
|
|||||||
B.btnAction.addNegativeOnClickListener(onClickListener)
|
B.btnAction.addNegativeOnClickListener(onClickListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallbackProp
|
||||||
|
fun installAction(onClickListener: OnClickListener?) {
|
||||||
|
B.btnAction.addInstallOnClickListener(onClickListener)
|
||||||
|
}
|
||||||
|
|
||||||
@CallbackProp
|
@CallbackProp
|
||||||
fun longClick(onClickListener: OnLongClickListener?) {
|
fun longClick(onClickListener: OnLongClickListener?) {
|
||||||
B.layoutContent.setOnLongClickListener(onClickListener)
|
B.layoutContent.setOnLongClickListener(onClickListener)
|
||||||
@@ -156,5 +171,6 @@ class AppUpdateView : RelativeLayout {
|
|||||||
@OnViewRecycled
|
@OnViewRecycled
|
||||||
fun clear() {
|
fun clear() {
|
||||||
B.headerIndicator.removeCallbacks { }
|
B.headerIndicator.removeCallbacks { }
|
||||||
|
B.progressDownload.invisible()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,6 +52,7 @@ import com.tonyodev.fetch2.FetchGroup
|
|||||||
import nl.komponents.kovenant.task
|
import nl.komponents.kovenant.task
|
||||||
import nl.komponents.kovenant.ui.failUi
|
import nl.komponents.kovenant.ui.failUi
|
||||||
import nl.komponents.kovenant.ui.successUi
|
import nl.komponents.kovenant.ui.successUi
|
||||||
|
import org.apache.commons.io.FileUtils
|
||||||
|
|
||||||
class UpdatesFragment : BaseFragment() {
|
class UpdatesFragment : BaseFragment() {
|
||||||
|
|
||||||
@@ -103,17 +104,17 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
|
|
||||||
override fun onCompleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
override fun onCompleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||||
if (fetchGroup.groupDownloadProgress == 100) {
|
if (fetchGroup.groupDownloadProgress == 100) {
|
||||||
VM.updateDownload(groupId, fetchGroup)
|
VM.updateDownload(groupId, fetchGroup, isComplete = true)
|
||||||
install(download.tag!!, fetchGroup.downloads)
|
install(download.tag!!, fetchGroup.downloads)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCancelled(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
override fun onCancelled(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||||
VM.updateDownload(groupId, fetchGroup,true)
|
VM.updateDownload(groupId, fetchGroup, isCancelled = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDeleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
override fun onDeleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||||
VM.updateDownload(groupId, fetchGroup,true)
|
VM.updateDownload(groupId, fetchGroup, isCancelled = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,11 +128,11 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onDestroy() {
|
||||||
if (::fetch.isInitialized && ::fetchListener.isInitialized) {
|
if (::fetch.isInitialized && ::fetchListener.isInitialized) {
|
||||||
fetch.removeListener(fetchListener)
|
fetch.removeListener(fetchListener)
|
||||||
}
|
}
|
||||||
super.onPause()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
@@ -173,8 +174,20 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
UpdateHeaderViewModel_()
|
UpdateHeaderViewModel_()
|
||||||
.id("header_all")
|
.id("header_all")
|
||||||
.title("${updateFileMap.size} updates available")
|
.title("${updateFileMap.size} updates available")
|
||||||
.action(getString(R.string.action_update_all))
|
.action(
|
||||||
.click { _ -> updateAll() }
|
if (VM.updateAllEnqueued)
|
||||||
|
getString(R.string.action_cancel)
|
||||||
|
else
|
||||||
|
getString(R.string.action_update_all)
|
||||||
|
)
|
||||||
|
.click { _ ->
|
||||||
|
if (VM.updateAllEnqueued)
|
||||||
|
cancelAll()
|
||||||
|
else
|
||||||
|
updateAll()
|
||||||
|
|
||||||
|
requestModelBuild()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
updateFileMap.values.forEach { updateFile ->
|
updateFileMap.values.forEach { updateFile ->
|
||||||
@@ -189,6 +202,12 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
.positiveAction { _ -> updateSingle(updateFile.app) }
|
.positiveAction { _ -> updateSingle(updateFile.app) }
|
||||||
.negativeAction { _ -> cancelSingle(updateFile.app) }
|
.negativeAction { _ -> cancelSingle(updateFile.app) }
|
||||||
|
.installAction { _ ->
|
||||||
|
install(
|
||||||
|
updateFile.app.packageName,
|
||||||
|
updateFile.group?.downloads
|
||||||
|
)
|
||||||
|
}
|
||||||
.state(updateFile.state)
|
.state(updateFile.state)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -229,19 +248,35 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
|
|
||||||
private fun updateAll() {
|
private fun updateAll() {
|
||||||
updateFileMap.values.forEach { updateSingle(it.app) }
|
updateFileMap.values.forEach { updateSingle(it.app) }
|
||||||
|
VM.updateAllEnqueued = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cancelAll() {
|
||||||
|
VM.updateAllEnqueued = false
|
||||||
|
updateFileMap.values.forEach { fetch.cancelGroup(it.app.id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun install(packageName: String, files: List<Download>) {
|
private fun install(packageName: String, files: List<Download>?) {
|
||||||
task {
|
files?.let { downloads ->
|
||||||
AppInstaller(requireContext())
|
var filesExist = true
|
||||||
.getPreferredInstaller()
|
|
||||||
.install(
|
downloads.forEach { download ->
|
||||||
packageName,
|
filesExist = filesExist && FileUtils.getFile(download.file).exists()
|
||||||
files
|
}
|
||||||
.filter { it.file.endsWith(".apk") }
|
|
||||||
.map { it.file }.toList()
|
if (filesExist) {
|
||||||
)
|
task {
|
||||||
|
AppInstaller(requireContext())
|
||||||
|
.getPreferredInstaller()
|
||||||
|
.install(
|
||||||
|
packageName,
|
||||||
|
files
|
||||||
|
.filter { it.file.endsWith(".apk") }
|
||||||
|
.map { it.file }.toList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class UpdatesViewModel(application: Application) : BaseAppsViewModel(application
|
|||||||
|
|
||||||
var updateFileMap: MutableMap<Int, UpdateFile> = mutableMapOf()
|
var updateFileMap: MutableMap<Int, UpdateFile> = mutableMapOf()
|
||||||
var liveUpdateData: MutableLiveData<MutableMap<Int, UpdateFile>> = MutableLiveData()
|
var liveUpdateData: MutableLiveData<MutableMap<Int, UpdateFile>> = MutableLiveData()
|
||||||
|
var updateAllEnqueued: Boolean = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
EventBus.getDefault().register(this)
|
EventBus.getDefault().register(this)
|
||||||
@@ -99,6 +100,9 @@ class UpdatesViewModel(application: Application) : BaseAppsViewModel(application
|
|||||||
when (event) {
|
when (event) {
|
||||||
is InstallerEvent.Success -> {
|
is InstallerEvent.Success -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
is InstallerEvent.Cancelled -> {
|
||||||
|
|
||||||
}
|
}
|
||||||
is InstallerEvent.Failed -> {
|
is InstallerEvent.Failed -> {
|
||||||
val packageName = event.packageName
|
val packageName = event.packageName
|
||||||
@@ -114,13 +118,25 @@ class UpdatesViewModel(application: Application) : BaseAppsViewModel(application
|
|||||||
liveUpdateData.postValue(updateFileMap)
|
liveUpdateData.postValue(updateFileMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateDownload(id: Int, group: FetchGroup?, isCancelled: Boolean = false) {
|
fun updateDownload(
|
||||||
if (isCancelled) {
|
id: Int,
|
||||||
updateFileMap[id]?.state = State.IDLE
|
group: FetchGroup?,
|
||||||
updateFileMap[id]?.group = null
|
isCancelled: Boolean = false,
|
||||||
} else {
|
isComplete: Boolean = false
|
||||||
updateFileMap[id]?.state = State.PROGRESS
|
) {
|
||||||
updateFileMap[id]?.group = group
|
when {
|
||||||
|
isCancelled -> {
|
||||||
|
updateFileMap[id]?.state = State.IDLE
|
||||||
|
updateFileMap[id]?.group = null
|
||||||
|
}
|
||||||
|
isComplete -> {
|
||||||
|
updateFileMap[id]?.state = State.COMPLETE
|
||||||
|
updateFileMap[id]?.group = group
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
updateFileMap[id]?.state = State.PROGRESS
|
||||||
|
updateFileMap[id]?.group = group
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
liveUpdateData.postValue(updateFileMap)
|
liveUpdateData.postValue(updateFileMap)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?selectableItemBackground"
|
android:background="?selectableItemBackground"
|
||||||
@@ -52,20 +53,15 @@
|
|||||||
android:layout_width="@dimen/icon_size_medium"
|
android:layout_width="@dimen/icon_size_medium"
|
||||||
android:layout_height="@dimen/icon_size_medium" />
|
android:layout_height="@dimen/icon_size_medium" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<ProgressBar
|
||||||
android:id="@+id/txt_progress_percent"
|
android:id="@+id/progress_download"
|
||||||
android:layout_width="match_parent"
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
android:layout_height="match_parent"
|
android:layout_width="@dimen/icon_size_medium"
|
||||||
|
android:layout_height="@dimen/icon_size_medium"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:visibility="gone"
|
android:progressDrawable="@drawable/progressbar_bg"
|
||||||
android:background="@drawable/bg_rounded"
|
android:visibility="invisible"
|
||||||
android:gravity="center"
|
tools:progress="40" />
|
||||||
android:paddingStart="@dimen/padding_normal"
|
|
||||||
android:paddingEnd="@dimen/padding_normal"
|
|
||||||
android:text="0%"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textSize="12sp"
|
|
||||||
app:fontFamily="@font/gilroy_extra_bold" />
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
|||||||
@@ -67,8 +67,20 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/action_cancel"
|
android:text="@string/action_cancel"
|
||||||
android:textAppearance="@style/TextAppearance.Aurora.Line1"
|
android:textAppearance="@style/TextAppearance.Aurora.Line1" />
|
||||||
android:textColor="@color/colorRed" />
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_install"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/action_install"
|
||||||
|
android:textAppearance="@style/TextAppearance.Aurora.Line1" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</ViewFlipper>
|
</ViewFlipper>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user