Improve app updates page [1/2]
This commit is contained in:
@@ -23,3 +23,11 @@ enum class AccountType {
|
|||||||
ANONYMOUS,
|
ANONYMOUS,
|
||||||
GOOGLE
|
GOOGLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
IDLE,
|
||||||
|
QUEUED,
|
||||||
|
PROGRESS,
|
||||||
|
COMPLETE,
|
||||||
|
CANCELED
|
||||||
|
}
|
||||||
|
|||||||
49
app/src/main/java/com/aurora/store/data/model/UpdateFile.kt
Normal file
49
app/src/main/java/com/aurora/store/data/model/UpdateFile.kt
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Aurora Store
|
||||||
|
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||||
|
*
|
||||||
|
* Aurora Store is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Aurora Store is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.aurora.store.data.model
|
||||||
|
|
||||||
|
import com.aurora.gplayapi.data.models.App
|
||||||
|
import com.aurora.store.State
|
||||||
|
import com.tonyodev.fetch2.FetchGroup
|
||||||
|
|
||||||
|
data class UpdateFile(val app: App) {
|
||||||
|
|
||||||
|
var group: FetchGroup? = null
|
||||||
|
var state: State = State.IDLE
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return app.id
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return when (other) {
|
||||||
|
is UpdateFile -> other.app.id == app.id
|
||||||
|
&& other.state == state
|
||||||
|
&& isGroupSame(group, other.group)
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isGroupSame(oldGroup: FetchGroup?, newGroup: FetchGroup?): Boolean {
|
||||||
|
if (oldGroup != null && newGroup == null)
|
||||||
|
return true
|
||||||
|
return oldGroup?.groupDownloadProgress != newGroup?.groupDownloadProgress
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ import com.aurora.extensions.getString
|
|||||||
import com.aurora.extensions.isLAndAbove
|
import com.aurora.extensions.isLAndAbove
|
||||||
import com.aurora.extensions.runOnUiThread
|
import com.aurora.extensions.runOnUiThread
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.State
|
||||||
import com.aurora.store.databinding.ViewActionButtonBinding
|
import com.aurora.store.databinding.ViewActionButtonBinding
|
||||||
import nl.komponents.kovenant.task
|
import nl.komponents.kovenant.task
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@@ -81,6 +82,20 @@ class ActionButton : RelativeLayout {
|
|||||||
R.drawable.ic_check
|
R.drawable.ic_check
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val stateBackground =
|
||||||
|
when (typedArray.getString(R.styleable.ActionButton_btnActionBackground)) {
|
||||||
|
"0" -> R.drawable.bg_state_outline
|
||||||
|
"1" -> R.drawable.bg_state_outline_rounded
|
||||||
|
"2" -> R.drawable.bg_state_flat
|
||||||
|
"3" -> R.drawable.bg_state_flat_rounded
|
||||||
|
"4" -> null
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
stateBackground?.let {
|
||||||
|
B.root.background = ContextCompat.getDrawable(context, it)
|
||||||
|
}
|
||||||
|
|
||||||
val stateColor = ContextCompat.getColor(context, btnTxtColor)
|
val stateColor = ContextCompat.getColor(context, btnTxtColor)
|
||||||
|
|
||||||
B.btn.text = btnTxt
|
B.btn.text = btnTxt
|
||||||
@@ -108,6 +123,7 @@ class ActionButton : RelativeLayout {
|
|||||||
State.IDLE -> 0
|
State.IDLE -> 0
|
||||||
State.PROGRESS -> 1
|
State.PROGRESS -> 1
|
||||||
State.COMPLETE -> 2
|
State.COMPLETE -> 2
|
||||||
|
else -> 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if (B.viewFlipper.displayedChild != displayChild) {
|
if (B.viewFlipper.displayedChild != displayChild) {
|
||||||
@@ -127,13 +143,7 @@ class ActionButton : RelativeLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addOnClickListener(onClickListener: OnClickListener) {
|
fun addOnClickListener(onClickListener: OnClickListener?) {
|
||||||
B.btn.setOnClickListener(onClickListener)
|
B.btn.setOnClickListener(onClickListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class State {
|
|
||||||
IDLE,
|
|
||||||
PROGRESS,
|
|
||||||
COMPLETE,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Aurora Store
|
||||||
|
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||||
|
*
|
||||||
|
* Aurora Store is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Aurora Store is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.aurora.store.view.custom.layouts.button
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.widget.RelativeLayout
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import com.aurora.extensions.getString
|
||||||
|
import com.aurora.extensions.runOnUiThread
|
||||||
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.State
|
||||||
|
import com.aurora.store.databinding.ViewUpdateButtonBinding
|
||||||
|
|
||||||
|
class UpdateButton : RelativeLayout {
|
||||||
|
|
||||||
|
private lateinit var B: ViewUpdateButtonBinding
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {
|
||||||
|
init(context, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||||
|
context,
|
||||||
|
attrs,
|
||||||
|
defStyleAttr
|
||||||
|
) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet?,
|
||||||
|
defStyleAttr: Int,
|
||||||
|
defStyleRes: Int
|
||||||
|
) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
val view = inflate(context, R.layout.view_update_button, this)
|
||||||
|
B = ViewUpdateButtonBinding.bind(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setText(text: String) {
|
||||||
|
B.viewFlipper.displayedChild = 0
|
||||||
|
B.btnPositive.text = text
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setText(text: Int) {
|
||||||
|
B.viewFlipper.displayedChild = 0
|
||||||
|
B.btnPositive.text = getString(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateState(state: State) {
|
||||||
|
val displayChild = when (state) {
|
||||||
|
State.IDLE, State.COMPLETE, State.CANCELED -> 0
|
||||||
|
State.QUEUED -> 1
|
||||||
|
State.PROGRESS -> 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (B.viewFlipper.displayedChild != displayChild) {
|
||||||
|
runOnUiThread {
|
||||||
|
B.viewFlipper.displayedChild = displayChild
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addPositiveOnClickListener(onClickListener: OnClickListener?) {
|
||||||
|
B.btnPositive.setOnClickListener(onClickListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addNegativeOnClickListener(onClickListener: OnClickListener?) {
|
||||||
|
B.btnNegative.setOnClickListener(onClickListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,17 +21,19 @@ package com.aurora.store.view.epoxy.views.app
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.widget.CompoundButton
|
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import com.airbnb.epoxy.CallbackProp
|
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.clear
|
import com.aurora.extensions.hide
|
||||||
import com.aurora.extensions.load
|
import com.aurora.extensions.load
|
||||||
import com.aurora.gplayapi.data.models.App
|
import com.aurora.extensions.px
|
||||||
|
import com.aurora.extensions.show
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.State
|
||||||
|
import com.aurora.store.data.model.UpdateFile
|
||||||
import com.aurora.store.databinding.ViewAppUpdateBinding
|
import com.aurora.store.databinding.ViewAppUpdateBinding
|
||||||
import com.aurora.store.util.CommonUtil
|
import com.aurora.store.util.CommonUtil
|
||||||
import com.aurora.store.view.epoxy.views.BaseView
|
import com.aurora.store.view.epoxy.views.BaseView
|
||||||
@@ -45,7 +47,6 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withC
|
|||||||
class AppUpdateView : RelativeLayout {
|
class AppUpdateView : RelativeLayout {
|
||||||
|
|
||||||
private lateinit var B: ViewAppUpdateBinding
|
private lateinit var B: ViewAppUpdateBinding
|
||||||
private var expanded: Boolean = false
|
|
||||||
|
|
||||||
constructor(context: Context?) : super(context) {
|
constructor(context: Context?) : super(context) {
|
||||||
init(context, null)
|
init(context, null)
|
||||||
@@ -69,43 +70,67 @@ class AppUpdateView : RelativeLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ModelProp
|
@ModelProp
|
||||||
fun app(app: App) {
|
fun updateFile(updateFile: UpdateFile?) {
|
||||||
B.txtLine1.text = app.displayName
|
if (updateFile != null) {
|
||||||
B.imgIcon.load(app.iconArtwork.url, withCrossFade()) {
|
|
||||||
placeholder(R.drawable.bg_placeholder)
|
|
||||||
transform(RoundedCorners(25))
|
|
||||||
}
|
|
||||||
|
|
||||||
B.txtLine2.text = app.developerName
|
/*Inflate App details*/
|
||||||
B.txtLine3.text = ("${CommonUtil.addSiPrefix(app.size)} • ${app.updatedOn}")
|
with(updateFile.app) {
|
||||||
B.txtLine4.text = ("v${app.versionName}.${app.versionCode}")
|
B.txtLine1.text = displayName
|
||||||
B.txtChangelog.text = if (app.changes.isNotEmpty())
|
B.imgIcon.load(iconArtwork.url, withCrossFade()) {
|
||||||
HtmlCompat.fromHtml(
|
placeholder(R.drawable.bg_placeholder)
|
||||||
app.changes,
|
transform(RoundedCorners(8.px.toInt()))
|
||||||
HtmlCompat.FROM_HTML_OPTION_USE_CSS_COLORS
|
}
|
||||||
)
|
|
||||||
else
|
|
||||||
context.getString(R.string.details_changelog_unavailable)
|
|
||||||
|
|
||||||
B.headerIndicator.setOnClickListener {
|
B.txtLine2.text = developerName
|
||||||
B.expansionLayout.let {
|
B.txtLine3.text = ("${CommonUtil.addSiPrefix(size)} • $updatedOn")
|
||||||
if (it.isExpanded) {
|
B.txtLine4.text = ("v${versionName}.${versionCode}")
|
||||||
it.collapse(true)
|
B.txtChangelog.text = if (changes.isNotEmpty())
|
||||||
} else {
|
HtmlCompat.fromHtml(
|
||||||
it.expand(true)
|
changes,
|
||||||
|
HtmlCompat.FROM_HTML_OPTION_USE_CSS_COLORS
|
||||||
|
)
|
||||||
|
else
|
||||||
|
context.getString(R.string.details_changelog_unavailable)
|
||||||
|
|
||||||
|
B.headerIndicator.setOnClickListener {
|
||||||
|
B.expansionLayout.let {
|
||||||
|
if (it.isExpanded) {
|
||||||
|
it.collapse(true)
|
||||||
|
} else {
|
||||||
|
it.expand(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Inflate Download details*/
|
||||||
|
updateFile.group?.let {
|
||||||
|
if (updateFile.state == State.PROGRESS) {
|
||||||
|
val progress = it.groupDownloadProgress
|
||||||
|
if (progress > 0) {
|
||||||
|
if (progress == 100) {
|
||||||
|
B.txtProgressPercent.hide()
|
||||||
|
} else {
|
||||||
|
B.txtProgressPercent.show()
|
||||||
|
B.txtProgressPercent.text = ("${progress}%")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (updateFile.state == State.IDLE || updateFile.state == State.CANCELED) {
|
||||||
|
B.btnAction.updateState(State.IDLE)
|
||||||
|
B.txtProgressPercent.text = ("0%")
|
||||||
|
B.txtProgressPercent.hide()
|
||||||
|
} else if (updateFile.state == State.QUEUED) {
|
||||||
|
B.btnAction.updateState(State.QUEUED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ModelProp
|
@ModelProp
|
||||||
fun markChecked(isChecked: Boolean) {
|
fun state(state: State?) {
|
||||||
B.checkbox.isChecked = isChecked
|
state?.let {
|
||||||
}
|
B.btnAction.updateState(it)
|
||||||
|
}
|
||||||
@CallbackProp
|
|
||||||
fun checked(onCheckedChangeListener: CompoundButton.OnCheckedChangeListener?) {
|
|
||||||
B.checkbox.setOnCheckedChangeListener(onCheckedChangeListener)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallbackProp
|
@CallbackProp
|
||||||
@@ -113,6 +138,16 @@ class AppUpdateView : RelativeLayout {
|
|||||||
B.layoutContent.setOnClickListener(onClickListener)
|
B.layoutContent.setOnClickListener(onClickListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallbackProp
|
||||||
|
fun positiveAction(onClickListener: OnClickListener?) {
|
||||||
|
B.btnAction.addPositiveOnClickListener(onClickListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallbackProp
|
||||||
|
fun negativeAction(onClickListener: OnClickListener?) {
|
||||||
|
B.btnAction.addNegativeOnClickListener(onClickListener)
|
||||||
|
}
|
||||||
|
|
||||||
@CallbackProp
|
@CallbackProp
|
||||||
fun longClick(onClickListener: OnLongClickListener?) {
|
fun longClick(onClickListener: OnLongClickListener?) {
|
||||||
B.layoutContent.setOnLongClickListener(onClickListener)
|
B.layoutContent.setOnLongClickListener(onClickListener)
|
||||||
@@ -120,7 +155,6 @@ class AppUpdateView : RelativeLayout {
|
|||||||
|
|
||||||
@OnViewRecycled
|
@OnViewRecycled
|
||||||
fun clear() {
|
fun clear() {
|
||||||
B.imgIcon.clear()
|
|
||||||
B.headerIndicator.removeCallbacks { }
|
B.headerIndicator.removeCallbacks { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,8 +35,6 @@ import java.lang.reflect.Modifier
|
|||||||
|
|
||||||
open class BaseFragment : Fragment() {
|
open class BaseFragment : Fragment() {
|
||||||
|
|
||||||
protected lateinit var app: App
|
|
||||||
|
|
||||||
var gson: Gson = GsonBuilder().excludeFieldsWithModifiers(
|
var gson: Gson = GsonBuilder().excludeFieldsWithModifiers(
|
||||||
Modifier.TRANSIENT
|
Modifier.TRANSIENT
|
||||||
).create()
|
).create()
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import com.aurora.gplayapi.helpers.AppDetailsHelper
|
|||||||
import com.aurora.gplayapi.helpers.PurchaseHelper
|
import com.aurora.gplayapi.helpers.PurchaseHelper
|
||||||
import com.aurora.store.MainActivity
|
import com.aurora.store.MainActivity
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.State
|
||||||
import com.aurora.store.data.downloader.DownloadManager
|
import com.aurora.store.data.downloader.DownloadManager
|
||||||
import com.aurora.store.data.downloader.RequestBuilder
|
import com.aurora.store.data.downloader.RequestBuilder
|
||||||
import com.aurora.store.data.event.BusEvent
|
import com.aurora.store.data.event.BusEvent
|
||||||
@@ -47,7 +48,6 @@ import com.aurora.store.data.network.HttpClient
|
|||||||
import com.aurora.store.data.providers.AuthProvider
|
import com.aurora.store.data.providers.AuthProvider
|
||||||
import com.aurora.store.databinding.ActivityDetailsBinding
|
import com.aurora.store.databinding.ActivityDetailsBinding
|
||||||
import com.aurora.store.util.*
|
import com.aurora.store.util.*
|
||||||
import com.aurora.store.view.custom.layouts.button.ActionButton
|
|
||||||
import com.aurora.store.view.ui.downloads.DownloadActivity
|
import com.aurora.store.view.ui.downloads.DownloadActivity
|
||||||
import com.aurora.store.view.ui.sheets.InstallErrorDialogSheet
|
import com.aurora.store.view.ui.sheets.InstallErrorDialogSheet
|
||||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||||
@@ -125,7 +125,7 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
|||||||
event.extra
|
event.extra
|
||||||
).show(supportFragmentManager, "SED")
|
).show(supportFragmentManager, "SED")
|
||||||
attachActions()
|
attachActions()
|
||||||
updateActionState(ActionButton.State.IDLE)
|
updateActionState(State.IDLE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@@ -234,7 +234,7 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
|||||||
checkAndSetupInstall()
|
checkAndSetupInstall()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateActionState(state: ActionButton.State) {
|
private fun updateActionState(state: State) {
|
||||||
B.layoutDetailsInstall.btnDownload.updateState(state)
|
B.layoutDetailsInstall.btnDownload.updateState(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
|||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun install(files: List<Download>) {
|
private fun install(files: List<Download>) {
|
||||||
updateActionState(ActionButton.State.IDLE)
|
updateActionState(State.IDLE)
|
||||||
|
|
||||||
task {
|
task {
|
||||||
AppInstaller(this)
|
AppInstaller(this)
|
||||||
@@ -398,7 +398,7 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun purchase() {
|
private fun purchase() {
|
||||||
updateActionState(ActionButton.State.PROGRESS)
|
updateActionState(State.PROGRESS)
|
||||||
|
|
||||||
task {
|
task {
|
||||||
val authData = AuthProvider
|
val authData = AuthProvider
|
||||||
@@ -424,10 +424,10 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
|||||||
enqueue(files)
|
enqueue(files)
|
||||||
} else {
|
} else {
|
||||||
Log.e("Failed to download : ${app.displayName}")
|
Log.e("Failed to download : ${app.displayName}")
|
||||||
updateActionState(ActionButton.State.IDLE)
|
updateActionState(State.IDLE)
|
||||||
}
|
}
|
||||||
} failUi {
|
} failUi {
|
||||||
updateActionState(ActionButton.State.IDLE)
|
updateActionState(State.IDLE)
|
||||||
var reason = "Unknown"
|
var reason = "Unknown"
|
||||||
|
|
||||||
when (it) {
|
when (it) {
|
||||||
@@ -477,7 +477,7 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
|||||||
Log.i("Downloading Apks : %s", app.displayName)
|
Log.i("Downloading Apks : %s", app.displayName)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
updateActionState(ActionButton.State.IDLE)
|
updateActionState(State.IDLE)
|
||||||
expandBottomSheet(getString(R.string.purchase_session_expired))
|
expandBottomSheet(getString(R.string.purchase_session_expired))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -521,7 +521,7 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
|||||||
|
|
||||||
with(B.layoutDetailsInstall) {
|
with(B.layoutDetailsInstall) {
|
||||||
txtPurchaseError.text = message
|
txtPurchaseError.text = message
|
||||||
btnDownload.updateState(ActionButton.State.IDLE)
|
btnDownload.updateState(State.IDLE)
|
||||||
if (app.isFree)
|
if (app.isFree)
|
||||||
btnDownload.setText(R.string.action_install)
|
btnDownload.setText(R.string.action_install)
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -25,20 +25,21 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import com.aurora.Constants
|
import com.aurora.Constants
|
||||||
|
import com.aurora.extensions.toast
|
||||||
import com.aurora.gplayapi.data.models.App
|
import com.aurora.gplayapi.data.models.App
|
||||||
import com.aurora.gplayapi.data.models.AuthData
|
import com.aurora.gplayapi.data.models.AuthData
|
||||||
import com.aurora.gplayapi.helpers.PurchaseHelper
|
import com.aurora.gplayapi.helpers.PurchaseHelper
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.State
|
||||||
import com.aurora.store.data.downloader.DownloadManager
|
import com.aurora.store.data.downloader.DownloadManager
|
||||||
import com.aurora.store.data.downloader.RequestBuilder
|
import com.aurora.store.data.downloader.RequestBuilder
|
||||||
import com.aurora.store.data.installer.AppInstaller
|
import com.aurora.store.data.installer.AppInstaller
|
||||||
|
import com.aurora.store.data.model.UpdateFile
|
||||||
import com.aurora.store.data.providers.AuthProvider
|
import com.aurora.store.data.providers.AuthProvider
|
||||||
import com.aurora.store.databinding.FragmentUpdatesBinding
|
import com.aurora.store.databinding.FragmentUpdatesBinding
|
||||||
import com.aurora.store.util.Log
|
import com.aurora.store.util.Log
|
||||||
import com.aurora.extensions.flushAndAdd
|
|
||||||
import com.aurora.extensions.toast
|
|
||||||
import com.aurora.store.view.epoxy.views.app.AppUpdateViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.UpdateHeaderViewModel_
|
import com.aurora.store.view.epoxy.views.UpdateHeaderViewModel_
|
||||||
|
import com.aurora.store.view.epoxy.views.app.AppUpdateViewModel_
|
||||||
import com.aurora.store.view.epoxy.views.app.NoAppViewModel_
|
import com.aurora.store.view.epoxy.views.app.NoAppViewModel_
|
||||||
import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_
|
import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_
|
||||||
import com.aurora.store.view.ui.commons.BaseFragment
|
import com.aurora.store.view.ui.commons.BaseFragment
|
||||||
@@ -63,7 +64,7 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
private lateinit var fetch: Fetch
|
private lateinit var fetch: Fetch
|
||||||
private lateinit var fetchListener: AbstractFetchGroupListener
|
private lateinit var fetchListener: AbstractFetchGroupListener
|
||||||
|
|
||||||
private val appList: MutableList<App> = mutableListOf()
|
private var updateFileMap: MutableMap<Int, UpdateFile> = mutableMapOf()
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
@@ -85,14 +86,36 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
|
|
||||||
fetch = DownloadManager.with(requireContext()).fetch
|
fetch = DownloadManager.with(requireContext()).fetch
|
||||||
fetchListener = object : AbstractFetchGroupListener() {
|
fetchListener = object : AbstractFetchGroupListener() {
|
||||||
|
|
||||||
|
override fun onAdded(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||||
|
VM.updateDownload(groupId, fetchGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProgress(
|
||||||
|
groupId: Int,
|
||||||
|
download: Download,
|
||||||
|
etaInMilliSeconds: Long,
|
||||||
|
downloadedBytesPerSecond: Long,
|
||||||
|
fetchGroup: FetchGroup
|
||||||
|
) {
|
||||||
|
VM.updateDownload(groupId, fetchGroup)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCompleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
override fun onCompleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||||
super.onCompleted(groupId, download, fetchGroup)
|
|
||||||
if (fetchGroup.groupDownloadProgress == 100) {
|
if (fetchGroup.groupDownloadProgress == 100) {
|
||||||
|
VM.updateDownload(groupId, fetchGroup)
|
||||||
install(download.tag!!, fetchGroup.downloads)
|
install(download.tag!!, fetchGroup.downloads)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
override fun onCancelled(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||||
|
VM.updateDownload(groupId, fetchGroup,true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||||
|
VM.updateDownload(groupId, fetchGroup,true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return B.root
|
return B.root
|
||||||
}
|
}
|
||||||
@@ -113,9 +136,10 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
VM.liveData.observe(viewLifecycleOwner, {
|
|
||||||
appList.flushAndAdd(it)
|
VM.liveUpdateData.observe(viewLifecycleOwner, {
|
||||||
updateController(it)
|
updateFileMap = it
|
||||||
|
updateController(updateFileMap)
|
||||||
B.swipeRefreshLayout.isRefreshing = false
|
B.swipeRefreshLayout.isRefreshing = false
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -126,10 +150,10 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
updateController(null)
|
updateController(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateController(appList: List<App>?) {
|
private fun updateController(updateFileMap: MutableMap<Int, UpdateFile>?) {
|
||||||
B.recycler.withModels {
|
B.recycler.withModels {
|
||||||
setFilterDuplicates(true)
|
setFilterDuplicates(true)
|
||||||
if (appList == null) {
|
if (updateFileMap == null) {
|
||||||
for (i in 1..6) {
|
for (i in 1..6) {
|
||||||
add(
|
add(
|
||||||
AppListViewShimmerModel_()
|
AppListViewShimmerModel_()
|
||||||
@@ -137,7 +161,7 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (appList.isEmpty()) {
|
if (updateFileMap.isEmpty()) {
|
||||||
add(
|
add(
|
||||||
NoAppViewModel_()
|
NoAppViewModel_()
|
||||||
.id("no_update")
|
.id("no_update")
|
||||||
@@ -146,44 +170,26 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
add(
|
add(
|
||||||
if (VM.selectedUpdates.isEmpty()) {
|
UpdateHeaderViewModel_()
|
||||||
UpdateHeaderViewModel_()
|
.id("header_all")
|
||||||
.id("header_all")
|
.title("${updateFileMap.size} updates available")
|
||||||
.title("${appList.size} updates available")
|
.action(getString(R.string.action_update_all))
|
||||||
.action(getString(R.string.action_update_all))
|
.click { _ -> updateAll() }
|
||||||
.click { v ->
|
|
||||||
updateAction(false)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
UpdateHeaderViewModel_()
|
|
||||||
.id("header_selected")
|
|
||||||
.title("${VM.selectedUpdates.size} updates selected")
|
|
||||||
.action(getString(R.string.action_update))
|
|
||||||
.click { v ->
|
|
||||||
updateAction(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
appList.forEach { app ->
|
updateFileMap.values.forEach { updateFile ->
|
||||||
add(
|
add(
|
||||||
AppUpdateViewModel_()
|
AppUpdateViewModel_()
|
||||||
.id(app.id)
|
.id(updateFile.hashCode())
|
||||||
.app(app)
|
.updateFile(updateFile)
|
||||||
.click { _ -> openDetailsActivity(app) }
|
.click { _ -> openDetailsActivity(updateFile.app) }
|
||||||
.longClick { _ ->
|
.longClick { _ ->
|
||||||
openAppMenuSheet(app)
|
openAppMenuSheet(updateFile.app)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
.markChecked(VM.selectedUpdates.contains(app.packageName))
|
.positiveAction { _ -> updateSingle(updateFile.app) }
|
||||||
.checked { _, isChecked ->
|
.negativeAction { _ -> cancelSingle(updateFile.app) }
|
||||||
if (isChecked)
|
.state(updateFile.state)
|
||||||
VM.selectedUpdates.add(app.packageName)
|
|
||||||
else
|
|
||||||
VM.selectedUpdates.remove(app.packageName)
|
|
||||||
|
|
||||||
requestModelBuild()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,65 +197,38 @@ class UpdatesFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateAction(selectedOnly: Boolean) {
|
private fun updateSingle(app: App) {
|
||||||
if (VM.isUpdating) {
|
|
||||||
requireContext().toast("Update in progress, let previous batch finish first")
|
VM.updateState(app.id, State.QUEUED)
|
||||||
} else {
|
|
||||||
if (selectedOnly) {
|
task {
|
||||||
updateSelected()
|
val files = purchaseHelper.purchase(
|
||||||
|
app.packageName,
|
||||||
|
app.versionCode,
|
||||||
|
app.offerType
|
||||||
|
)
|
||||||
|
|
||||||
|
files.map { RequestBuilder.buildRequest(requireContext(), app, it) }
|
||||||
|
} successUi {
|
||||||
|
val requests = it.filter { request -> request.url.isNotEmpty() }.toList()
|
||||||
|
if (requests.isNotEmpty()) {
|
||||||
|
fetch.enqueue(requests) {
|
||||||
|
Log.i("Updating ${app.displayName}")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updateAll()
|
requireContext().toast("Failed to update ${app.displayName}")
|
||||||
}
|
}
|
||||||
|
} failUi {
|
||||||
|
Log.e("Failed to update ${app.displayName}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun cancelSingle(app: App) {
|
||||||
|
fetch.cancelGroup(app.id)
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateAll() {
|
private fun updateAll() {
|
||||||
appList.forEach { app ->
|
updateFileMap.values.forEach { updateSingle(it.app) }
|
||||||
task {
|
|
||||||
val files = purchaseHelper.purchase(app.packageName, app.versionCode, app.offerType)
|
|
||||||
files.map { RequestBuilder.buildRequest(requireContext(), app, it) }
|
|
||||||
} successUi {
|
|
||||||
val requests = it.filter { request -> request.url.isNotEmpty() }.toList()
|
|
||||||
if (requests.isNotEmpty()) {
|
|
||||||
VM.isUpdating = true
|
|
||||||
fetch.enqueue(requests) {
|
|
||||||
Log.i("Updating ${app.displayName}")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
requireContext().toast("Failed to update ${app.displayName}")
|
|
||||||
}
|
|
||||||
} failUi {
|
|
||||||
Log.e("Failed to update ${app.displayName}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateSelected() {
|
|
||||||
val selectedPackages = VM.selectedUpdates
|
|
||||||
appList.forEach { app ->
|
|
||||||
if (selectedPackages.contains(app.packageName)) {
|
|
||||||
task {
|
|
||||||
val files = purchaseHelper.purchase(
|
|
||||||
app.packageName,
|
|
||||||
app.versionCode,
|
|
||||||
app.offerType
|
|
||||||
)
|
|
||||||
files.map { RequestBuilder.buildRequest(requireContext(), app, it) }
|
|
||||||
} successUi {
|
|
||||||
val requests = it.filter { request -> request.url.isNotEmpty() }.toList()
|
|
||||||
if (requests.isNotEmpty()) {
|
|
||||||
VM.isUpdating = true
|
|
||||||
fetch.enqueue(requests) {
|
|
||||||
Log.i("Updating ${app.displayName}")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
requireContext().toast("Failed to update ${app.displayName}")
|
|
||||||
}
|
|
||||||
} failUi {
|
|
||||||
Log.e("Failed to update ${app.displayName}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
|||||||
@@ -20,11 +20,15 @@
|
|||||||
package com.aurora.store.viewmodel.all
|
package com.aurora.store.viewmodel.all
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.aurora.gplayapi.data.models.App
|
import com.aurora.gplayapi.data.models.App
|
||||||
|
import com.aurora.store.State
|
||||||
import com.aurora.store.data.RequestState
|
import com.aurora.store.data.RequestState
|
||||||
import com.aurora.store.data.event.BusEvent
|
import com.aurora.store.data.event.BusEvent
|
||||||
import com.aurora.extensions.flushAndAdd
|
import com.aurora.store.data.event.InstallerEvent
|
||||||
|
import com.aurora.store.data.model.UpdateFile
|
||||||
|
import com.tonyodev.fetch2.FetchGroup
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
@@ -33,8 +37,8 @@ import org.greenrobot.eventbus.ThreadMode
|
|||||||
|
|
||||||
class UpdatesViewModel(application: Application) : BaseAppsViewModel(application) {
|
class UpdatesViewModel(application: Application) : BaseAppsViewModel(application) {
|
||||||
|
|
||||||
var selectedUpdates: MutableSet<String> = mutableSetOf()
|
var updateFileMap: MutableMap<Int, UpdateFile> = mutableMapOf()
|
||||||
var isUpdating: Boolean = false
|
var liveUpdateData: MutableLiveData<MutableMap<Int, UpdateFile>> = MutableLiveData()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
EventBus.getDefault().register(this)
|
EventBus.getDefault().register(this)
|
||||||
@@ -63,14 +67,17 @@ class UpdatesViewModel(application: Application) : BaseAppsViewModel(application
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}.also { apps ->
|
}.also { apps ->
|
||||||
appList.flushAndAdd(apps)
|
apps.forEach {
|
||||||
liveData.postValue(appList.sortedBy { it.displayName })
|
updateFileMap[it.id] = UpdateFile(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
liveUpdateData.postValue(updateFileMap)
|
||||||
requestState = RequestState.Complete
|
requestState = RequestState.Complete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||||
fun onEvent(event: BusEvent) {
|
fun onBusEvent(event: BusEvent) {
|
||||||
when (event) {
|
when (event) {
|
||||||
is BusEvent.InstallEvent -> {
|
is BusEvent.InstallEvent -> {
|
||||||
updateListAndPost(event.packageName)
|
updateListAndPost(event.packageName)
|
||||||
@@ -87,22 +94,44 @@ class UpdatesViewModel(application: Application) : BaseAppsViewModel(application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||||
|
fun onInstallerEvent(event: InstallerEvent) {
|
||||||
|
when (event) {
|
||||||
|
is InstallerEvent.Success -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
is InstallerEvent.Failed -> {
|
||||||
|
val packageName = event.packageName
|
||||||
|
packageName?.let {
|
||||||
|
updateDownload(packageName.hashCode(), null, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateState(id: Int, state: State) {
|
||||||
|
updateFileMap[id]?.state = state
|
||||||
|
liveUpdateData.postValue(updateFileMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateDownload(id: Int, group: FetchGroup?, isCancelled: Boolean = false) {
|
||||||
|
if (isCancelled) {
|
||||||
|
updateFileMap[id]?.state = State.IDLE
|
||||||
|
updateFileMap[id]?.group = null
|
||||||
|
} else {
|
||||||
|
updateFileMap[id]?.state = State.PROGRESS
|
||||||
|
updateFileMap[id]?.group = group
|
||||||
|
}
|
||||||
|
|
||||||
|
liveUpdateData.postValue(updateFileMap)
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateListAndPost(packageName: String) {
|
private fun updateListAndPost(packageName: String) {
|
||||||
//Remove from selected updates
|
//Remove from map
|
||||||
selectedUpdates.remove(packageName)
|
updateFileMap.remove(packageName.hashCode())
|
||||||
|
|
||||||
if (selectedUpdates.isEmpty())
|
|
||||||
isUpdating = false
|
|
||||||
|
|
||||||
//Remove from current update list
|
|
||||||
val updatedList = appList.filter {
|
|
||||||
it.packageName != packageName
|
|
||||||
}.toList()
|
|
||||||
|
|
||||||
appList.flushAndAdd(updatedList)
|
|
||||||
|
|
||||||
//Post new update list
|
//Post new update list
|
||||||
liveData.postValue(appList.sortedBy { it.displayName })
|
liveUpdateData.postValue(updateFileMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
|
|||||||
6
app/src/main/res/drawable/bg_state_flat.xml
Normal file
6
app/src/main/res/drawable/bg_state_flat.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
<solid android:color="?colorAccent" />
|
||||||
|
</shape>
|
||||||
6
app/src/main/res/drawable/bg_state_flat_rounded.xml
Normal file
6
app/src/main/res/drawable/bg_state_flat_rounded.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="28dp" />
|
||||||
|
<solid android:color="?colorAccent" />
|
||||||
|
</shape>
|
||||||
8
app/src/main/res/drawable/bg_state_outline.xml
Normal file
8
app/src/main/res/drawable/bg_state_outline.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="8dp"/>
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/colorPrimaryAlt" />
|
||||||
|
</shape>
|
||||||
8
app/src/main/res/drawable/bg_state_outline_rounded.xml
Normal file
8
app/src/main/res/drawable/bg_state_outline_rounded.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="28dp"/>
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/colorPrimaryAlt" />
|
||||||
|
</shape>
|
||||||
@@ -41,19 +41,40 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
|
||||||
android:id="@+id/img_icon"
|
<RelativeLayout
|
||||||
|
android:id="@+id/head_flipper"
|
||||||
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.AppCompatImageView
|
||||||
|
android:id="@+id/img_icon"
|
||||||
|
android:layout_width="@dimen/icon_size_medium"
|
||||||
|
android:layout_height="@dimen/icon_size_medium" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/txt_progress_percent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:background="@drawable/bg_rounded"
|
||||||
|
android:gravity="center"
|
||||||
|
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>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/txt_line1"
|
android:id="@+id/txt_line1"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_normal"
|
android:layout_marginStart="@dimen/margin_normal"
|
||||||
android:layout_marginEnd="@dimen/margin_normal"
|
android:layout_toStartOf="@+id/headerIndicator"
|
||||||
android:layout_toStartOf="@+id/layout_action"
|
android:layout_toEndOf="@id/head_flipper"
|
||||||
android:layout_toEndOf="@id/img_icon"
|
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textAppearance="@style/TextAppearance.Aurora.Line1" />
|
android:textAppearance="@style/TextAppearance.Aurora.Line1" />
|
||||||
@@ -91,41 +112,32 @@
|
|||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textAppearance="@style/TextAppearance.Aurora.Line3" />
|
android:textAppearance="@style/TextAppearance.Aurora.Line3" />
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/layout_action"
|
android:id="@+id/headerIndicator"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignBottom="@id/layout_action"
|
||||||
|
android:layout_toStartOf="@id/layout_action"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="@dimen/margin_small"
|
||||||
|
app:srcCompat="@drawable/ic_arrow_right"
|
||||||
|
app:tint="?colorControlNormal" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_action"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="@dimen/height_button"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal">
|
||||||
android:weightSum="2">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<com.aurora.store.view.custom.layouts.button.UpdateButton
|
||||||
android:id="@+id/headerIndicator"
|
android:id="@+id/btn_action"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content" />
|
||||||
android:layout_weight="1"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:padding="@dimen/margin_small"
|
|
||||||
app:srcCompat="@drawable/ic_arrow_right"
|
|
||||||
app:tint="?colorControlNormal" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="1dp"
|
|
||||||
android:layout_height="@dimen/icon_size_small"
|
|
||||||
android:layout_marginStart="@dimen/margin_small"
|
|
||||||
android:layout_marginEnd="@dimen/margin_small"
|
|
||||||
android:background="@drawable/bg_placeholder"
|
|
||||||
android:backgroundTint="?android:colorControlNormal" />
|
|
||||||
|
|
||||||
<com.google.android.material.checkbox.MaterialCheckBox
|
|
||||||
android:id="@+id/checkbox"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</com.github.florent37.expansionpanel.ExpansionHeader>
|
</com.github.florent37.expansionpanel.ExpansionHeader>
|
||||||
|
|||||||
78
app/src/main/res/layout/view_update_button.xml
Normal file
78
app/src/main/res/layout/view_update_button.xml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Aurora Store
|
||||||
|
~ Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||||
|
~
|
||||||
|
~ Aurora Store is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 2 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ Aurora Store is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
~
|
||||||
|
-->
|
||||||
|
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ViewFlipper
|
||||||
|
android:id="@+id/view_flipper"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inAnimation="@anim/fade_in"
|
||||||
|
android:outAnimation="@anim/fade_out"
|
||||||
|
tools:ignore="UselessParent">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnPositive"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/action_update"
|
||||||
|
android:textAppearance="@style/TextAppearance.Aurora.Line1" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnQueued"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:enabled="false"
|
||||||
|
android:text="@string/download_queued"
|
||||||
|
android:textAppearance="@style/TextAppearance.Aurora.Line1" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnNegative"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/action_cancel"
|
||||||
|
android:textAppearance="@style/TextAppearance.Aurora.Line1"
|
||||||
|
android:textColor="@color/colorRed" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</ViewFlipper>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user