AppDetails: Move action buttons to top of page

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Rahul Patel
2024-12-01 03:18:13 +05:30
committed by Aayush Gupta
parent 441364efab
commit 5209620cc4
14 changed files with 263 additions and 637 deletions

View File

@@ -23,12 +23,3 @@ enum class AccountType {
ANONYMOUS,
GOOGLE
}
enum class State {
IDLE,
QUEUED,
PROGRESS,
COMPLETE,
CANCELED,
INSTALLING,
}

View File

@@ -1,109 +0,0 @@
/*
* 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.content.res.ColorStateList
import android.util.AttributeSet
import android.widget.RelativeLayout
import androidx.core.content.ContextCompat
import com.aurora.store.R
import com.aurora.store.data.model.State
import com.aurora.store.databinding.ViewActionButtonBinding
class ActionButton : RelativeLayout {
private lateinit var binding: ViewActionButtonBinding
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)
}
private fun init(context: Context, attrs: AttributeSet?) {
val view = inflate(context, R.layout.view_action_button, this)
binding = ViewActionButtonBinding.bind(view)
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ActionButton)
val btnTxt = typedArray.getString(R.styleable.ActionButton_btnActionText)
val btnTxtColor = typedArray.getResourceId(
R.styleable.ActionButton_btnActionTextColor,
R.color.colorWhite
)
val stateIcon = typedArray.getResourceId(
R.styleable.ActionButton_btnActionIcon,
R.drawable.ic_check
)
val stateColor = ContextCompat.getColor(context, btnTxtColor)
binding.btn.text = btnTxt
binding.btn.setTextColor(stateColor)
binding.img.setImageDrawable(ContextCompat.getDrawable(context, stateIcon))
binding.img.imageTintList = ColorStateList.valueOf(stateColor)
typedArray.recycle()
}
fun setText(text: String) {
binding.viewFlipper.displayedChild = 0
binding.btn.text = text
}
fun setText(text: Int) {
binding.viewFlipper.displayedChild = 0
binding.btn.text = ContextCompat.getString(context, text)
}
fun setButtonState(enabled: Boolean = true) {
binding.btn.isEnabled = enabled
}
fun updateState(state: State) {
val displayChild = when (state) {
State.PROGRESS -> 1
State.COMPLETE -> 2
else -> 0
}
if (binding.viewFlipper.displayedChild != displayChild) {
binding.viewFlipper.displayedChild = displayChild
if (displayChild == 2) updateState(State.IDLE)
}
}
fun addOnClickListener(onClickListener: OnClickListener?) {
binding.btn.setOnClickListener(onClickListener)
}
}

View File

@@ -20,33 +20,40 @@
package com.aurora.store.view.ui.details
import android.animation.ObjectAnimator
import android.content.ActivityNotFoundException
import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.RelativeLayout
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import coil3.asDrawable
import coil3.load
import coil3.request.placeholder
import coil3.request.transformations
import coil3.transform.CircleCropTransformation
import coil3.transform.RoundedCornersTransformation
import com.aurora.Constants
import com.aurora.Constants.EXODUS_SUBMIT_PAGE
import com.aurora.extensions.browse
import com.aurora.extensions.hide
import com.aurora.extensions.invisible
import com.aurora.extensions.px
import com.aurora.extensions.requiresObbDir
import com.aurora.extensions.runOnUiThread
import com.aurora.extensions.share
@@ -66,7 +73,6 @@ import com.aurora.store.data.event.InstallerEvent
import com.aurora.store.data.installer.AppInstaller
import com.aurora.store.data.model.DownloadStatus
import com.aurora.store.data.model.PermissionType
import com.aurora.store.data.model.State
import com.aurora.store.data.model.ViewState
import com.aurora.store.data.model.ViewState.Loading.getDataAs
import com.aurora.store.data.providers.AuthProvider
@@ -75,6 +81,8 @@ import com.aurora.store.util.CertUtil
import com.aurora.store.util.CommonUtil
import com.aurora.store.util.PackageUtil
import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_SIMILAR
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_EXTENDED
import com.aurora.store.util.ShortcutManagerUtil
import com.aurora.store.view.custom.RatingView
import com.aurora.store.view.epoxy.controller.DetailsCarouselController
@@ -85,8 +93,6 @@ import com.aurora.store.view.epoxy.views.details.ScreenshotViewModel_
import com.aurora.store.view.ui.commons.BaseFragment
import com.aurora.store.viewmodel.details.AppDetailsViewModel
import com.aurora.store.viewmodel.details.DetailsClusterViewModel
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.filter
@@ -106,8 +112,8 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
@Inject
lateinit var authProvider: AuthProvider
private lateinit var bottomSheetBehavior: BottomSheetBehavior<LinearLayout>
private lateinit var app: App
private lateinit var iconDrawable: Drawable
private var streamBundle: StreamBundle? = StreamBundle()
@@ -117,11 +123,19 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
private var isUpdatable: Boolean = false
private var uninstallActionEnabled = false
private val tags = mutableListOf<String>()
private val isExtendedUpdateEnabled: Boolean
get() = Preferences.getBoolean(requireContext(), PREFERENCE_UPDATES_EXTENDED)
private val showSimilarApps: Boolean
get() = Preferences.getBoolean(requireContext(), PREFERENCE_SIMILAR)
private fun onEvent(event: Event) {
when (event) {
is InstallerEvent.Installed -> {
if (app.packageName == event.packageName) {
attachActions()
checkAndSetupInstall()
transformIcon(false)
binding.layoutDetailsToolbar.toolbar.menu.apply {
findItem(R.id.action_home_screen)?.isVisible =
ShortcutManagerUtil.canPinShortcut(requireContext(), app.packageName)
@@ -133,7 +147,8 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
is InstallerEvent.Uninstalled -> {
if (app.packageName == event.packageName) {
attachActions()
checkAndSetupInstall()
transformIcon(false)
binding.layoutDetailsToolbar.toolbar.menu.apply {
findItem(R.id.action_home_screen)?.isVisible = false
findItem(R.id.action_uninstall)?.isVisible = false
@@ -164,8 +179,7 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
is InstallerEvent.Installing -> {
if (event.packageName == app.packageName) {
attachActions()
updateActionState(State.INSTALLING)
checkAndSetupInstall()
}
}
@@ -178,23 +192,6 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Adjust margins for edgeToEdge display
ViewCompat.setOnApplyWindowInsetsListener(binding.layoutDetailsDev.root) { v, w ->
val insets = w.getInsets(WindowInsetsCompat.Type.navigationBars())
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin += insets.bottom
}
WindowInsetsCompat.CONSUMED
}
ViewCompat.setOnApplyWindowInsetsListener(binding.layoutDetailsInstall.viewFlipper) { v, w ->
val insets = w.getInsets(WindowInsetsCompat.Type.navigationBars())
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin += insets.bottom
}
WindowInsetsCompat.CONSUMED
}
if (args.app != null) {
app = args.app!!
inflatePartialApp()
@@ -232,17 +229,20 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
download?.let {
downloadStatus = it.downloadStatus
if (it.isFinished) flip(0) else flip(1)
when (it.downloadStatus) {
DownloadStatus.QUEUED -> {
updateProgress(it.progress)
}
DownloadStatus.DOWNLOADING -> {
updateSecondaryAction(true)
updateProgress(it.progress, it.speed, it.timeRemaining)
}
else -> {}
else -> {
transformIcon(false)
updateSecondaryAction(false)
}
}
}
}
@@ -368,12 +368,6 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
}
}
binding.layoutDetailsInstall.progressDownload.clipToOutline = true
binding.layoutDetailsInstall.imgCancel.setOnClickListener {
viewModel.cancelDownload(app)
if (downloadStatus != DownloadStatus.DOWNLOADING) flip(0)
}
viewLifecycleOwner.lifecycleScope.launch {
AuroraApp.events.busEvent.collect { onEvent(it) }
}
@@ -387,11 +381,6 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
super.onResume()
}
private fun attachActions() {
flip(0)
checkAndSetupInstall()
}
private fun attachToolbar() {
binding.layoutDetailsToolbar.toolbar.apply {
elevation = 0f
@@ -475,6 +464,9 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
imgIcon.load(app.iconArtwork.url) {
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(32F))
listener { _, result ->
result.image.asDrawable(resources).let { iconDrawable = it }
}
}
txtLine1.text = app.displayName
@@ -488,7 +480,7 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
txtLine3.text = ("${app.versionName} (${app.versionCode})")
packageName.text = app.packageName
val tags = mutableListOf<String>()
if (app.isFree)
tags.add(getString(R.string.details_free))
else
@@ -503,40 +495,6 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
}
}
private fun attachBottomSheet() {
binding.layoutDetailsInstall.apply {
viewFlipper.setInAnimation(requireContext(), R.anim.fade_in)
viewFlipper.setOutAnimation(requireContext(), R.anim.fade_out)
}
bottomSheetBehavior = BottomSheetBehavior.from(binding.layoutDetailsInstall.bottomSheet)
bottomSheetBehavior.isDraggable = false
bottomSheetBehavior.addBottomSheetCallback(object : BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
bottomSheetBehavior.setDraggable(true)
} else if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
bottomSheetBehavior.isDraggable = false
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
})
}
private fun updateActionState(state: State) {
runOnUiThread {
binding.layoutDetailsInstall.btnDownload.apply {
updateState(state)
if (state == State.INSTALLING) {
setButtonState(false)
setText(R.string.action_installing)
}
}
}
}
private fun openApp() {
val intent = PackageUtil.getLaunchIntent(requireContext(), app.packageName)
if (intent != null) {
@@ -552,28 +510,24 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
private fun startDownload() {
when (downloadStatus) {
DownloadStatus.DOWNLOADING -> {
flip(1)
toast("Already downloading")
}
else -> {
flip(1)
purchase()
}
}
}
private fun purchase() {
bottomSheetBehavior.isHideable = false
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
updateActionState(State.PROGRESS)
if (app.fileList.requiresObbDir()) {
if (permissionProvider.isGranted(PermissionType.STORAGE_MANAGER)) {
viewModel.download(app)
} else {
permissionProvider.request(PermissionType.STORAGE_MANAGER) {
if (it) viewModel.download(app) else flip(0)
if (it) viewModel.download(app) else {
// TODO: Ask for permission again or redirect to Permission Manager
}
}
}
} else {
@@ -583,108 +537,191 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
private fun updateProgress(progress: Int, speed: Long = -1, timeRemaining: Long = -1) {
runOnUiThread {
updatePrimaryAction(false)
updateSecondaryAction(true)
if (progress == 100) {
binding.layoutDetailsInstall.btnDownload.setText(getString(R.string.action_installing))
transformIcon(false)
binding.layoutDetailsApp.apply {
txtLine3.text = ("${app.versionName} (${app.versionCode})")
txtLine4.text = tags.joinToString(separator = "")
}
return@runOnUiThread
}
binding.layoutDetailsInstall.apply {
txtProgressPercent.text = ("${progress}%")
progressDownload.apply {
this.progress = progress
isIndeterminate = progress < 1
transformIcon(true)
binding.layoutDetailsApp.apply {
if (progress < 1) {
progressDownload.isIndeterminate = true
} else {
progressDownload.isIndeterminate = false
progressDownload.progress = progress
txtLine3.text = CommonUtil.getETAString(requireContext(), timeRemaining)
txtLine4.text = CommonUtil.getDownloadSpeedString(requireContext(), speed)
}
txtEta.text = CommonUtil.getETAString(requireContext(), timeRemaining)
txtSpeed.text = CommonUtil.getDownloadSpeedString(requireContext(), speed)
}
}
}
private fun checkAndSetupInstall() {
app.isInstalled = PackageUtil.isInstalled(requireContext(), app.packageName)
runOnUiThread {
binding.layoutDetailsInstall.btnDownload.let { btn ->
btn.setButtonState(true)
if (app.isInstalled) {
val isExtendedUpdateEnabled = Preferences.getBoolean(
requireContext(), Preferences.PREFERENCE_UPDATES_EXTENDED
)
val needsExtendedUpdate = !app.certificateSetList.any {
it.certificateSet in CertUtil.getEncodedCertificateHashes(
requireContext(), app.packageName
)
}
isUpdatable = PackageUtil.isUpdatable(
requireContext(),
app.packageName,
app.versionCode.toLong()
)
val installedVersion =
PackageUtil.getInstalledVersion(requireContext(), app.packageName)
if (isUpdatable && !needsExtendedUpdate || isUpdatable && isExtendedUpdateEnabled) {
binding.layoutDetailsApp.txtLine3.text =
("$installedVersion${app.versionName} (${app.versionCode})")
btn.setText(R.string.action_update)
btn.addOnClickListener {
if (app.versionCode == 0) {
toast(R.string.toast_app_unavailable)
} else {
startDownload()
}
}
} else {
binding.layoutDetailsApp.txtLine3.text = installedVersion
btn.setText(R.string.action_open)
btn.addOnClickListener { openApp() }
}
if (!uninstallActionEnabled) {
binding.layoutDetailsToolbar.toolbar.invalidateMenu()
}
} else {
if (downloadStatus in DownloadStatus.running) {
flip(1)
} else if (app.isFree) {
btn.setText(R.string.action_install)
} else {
btn.setText(app.price)
}
btn.addOnClickListener {
if (!permissionProvider.isGranted(PermissionType.INSTALL_UNKNOWN_APPS)) {
permissionProvider.request(PermissionType.INSTALL_UNKNOWN_APPS) {
if (it) {
btn.setText(R.string.download_metadata)
startDownload()
}
}
} else if (authProvider.isAnonymous && !app.isFree) {
toast(R.string.toast_purchase_blocked)
} else if (app.versionCode == 0) {
toast(R.string.toast_app_unavailable)
} else {
btn.setText(R.string.download_metadata)
startDownload()
}
}
if (uninstallActionEnabled) {
binding.layoutDetailsToolbar.toolbar.invalidateMenu()
}
}
private fun updatePrimaryAction(enabled: Boolean = false) {
binding.layoutDetailsApp.btnPrimaryAction.apply {
isEnabled = enabled
text = if (app.isInstalled) {
getString(R.string.action_open)
} else {
getString(R.string.action_install)
}
}
}
@Synchronized
private fun flip(nextView: Int) {
private fun updateSecondaryAction(enabled: Boolean = false) {
runOnUiThread {
val displayChild = binding.layoutDetailsInstall.viewFlipper.displayedChild
if (displayChild != nextView) {
binding.layoutDetailsInstall.viewFlipper.displayedChild = nextView
if (nextView == 0) checkAndSetupInstall()
binding.layoutDetailsApp.btnSecondaryAction.apply {
isEnabled = enabled
isVisible = enabled
text = getString(R.string.action_cancel)
setOnClickListener {
viewModel.cancelDownload(app)
updatePrimaryAction(true)
}
}
}
}
private fun transformIcon(ongoing: Boolean = false) {
val scaleFactor = if (ongoing) 0.75f else 1f
val isDownloadVisible = binding.layoutDetailsApp.progressDownload.isShown
// Avoids flickering when the download is in progress
if (isDownloadVisible && scaleFactor != 1f)
return
if (!isDownloadVisible && scaleFactor == 1f)
return
if (scaleFactor == 1f) {
binding.layoutDetailsApp.progressDownload.invisible()
} else {
binding.layoutDetailsApp.progressDownload.show()
}
val scale = listOf(
ObjectAnimator.ofFloat(binding.layoutDetailsApp.imgIcon, "scaleX", scaleFactor),
ObjectAnimator.ofFloat(binding.layoutDetailsApp.imgIcon, "scaleY", scaleFactor)
)
scale.forEach { animation ->
animation.apply {
interpolator = AccelerateDecelerateInterpolator()
duration = 250
start()
}
}
iconDrawable?.let {
binding.layoutDetailsApp.imgIcon.load(it) {
transformations(
if (scaleFactor == 1f)
RoundedCornersTransformation(8.px.toFloat())
else
CircleCropTransformation()
)
}
}
}
@Synchronized
private fun checkAndSetupInstall() {
runOnUiThread {
app.isInstalled = PackageUtil.isInstalled(requireContext(), app.packageName)
if (app.isInstalled) {
val needsExtendedUpdate = !app.certificateSetList.any {
it.certificateSet in CertUtil.getEncodedCertificateHashes(
requireContext(),
app.packageName
)
}
isUpdatable = PackageUtil.isUpdatable(
requireContext(),
app.packageName,
app.versionCode.toLong()
)
val installedVersion = PackageUtil.getInstalledVersion(
requireContext(),
app.packageName
)
if ((isUpdatable && !needsExtendedUpdate) || (isUpdatable && isExtendedUpdateEnabled)) {
binding.layoutDetailsApp.apply {
txtLine3.text =
("$installedVersion${app.versionName} (${app.versionCode})")
txtLine4.text = tags.joinToString(separator = "")
btnPrimaryAction.apply {
isEnabled = true
setText(R.string.action_update)
setOnClickListener {
if (app.versionCode == 0) {
toast(R.string.toast_app_unavailable)
btnPrimaryAction.setText(R.string.status_unavailable)
} else {
startDownload()
}
}
}
}
} else {
binding.layoutDetailsApp.apply {
txtLine3.text = installedVersion
btnPrimaryAction.apply {
isEnabled = true
setText(R.string.action_open)
setOnClickListener { openApp() }
}
}
}
if (!uninstallActionEnabled) {
binding.layoutDetailsToolbar.toolbar.invalidateMenu()
}
} else {
if (downloadStatus in DownloadStatus.running) {
updateProgress(-1)
} else if (app.isFree) {
binding.layoutDetailsApp.btnPrimaryAction.setText(R.string.action_install)
} else {
binding.layoutDetailsApp.btnPrimaryAction.text = app.price
}
binding.layoutDetailsApp.btnPrimaryAction.setOnClickListener {
if (authProvider.isAnonymous && !app.isFree) {
toast(R.string.toast_purchase_blocked)
return@setOnClickListener
} else if (app.versionCode == 0) {
toast(R.string.toast_app_unavailable)
return@setOnClickListener
}
if (!permissionProvider.isGranted(PermissionType.INSTALL_UNKNOWN_APPS)) {
permissionProvider.request(PermissionType.INSTALL_UNKNOWN_APPS) {
if (it) {
startDownload()
} else {
toast(R.string.permissions_denied)
// TODO: Warn & redirect to Permission Manager
}
}
} else {
startDownload()
}
}
if (uninstallActionEnabled) {
binding.layoutDetailsToolbar.toolbar.invalidateMenu()
}
}
}
}
@@ -692,8 +729,7 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
private fun inflatePartialApp() {
if (::app.isInitialized) {
attachHeader()
attachBottomSheet()
attachActions()
checkAndSetupInstall()
}
}
@@ -717,7 +753,7 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
inflateBetaSubscription(app)
}
if (Preferences.getBoolean(requireContext(), Preferences.PREFERENCE_SIMILAR)) {
if (showSimilarApps) {
inflateAppStream(app)
}
}

View File

@@ -1,29 +0,0 @@
<?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/>.
~
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners
android:topLeftRadius="14dp"
android:topRightRadius="14dp" />
<solid android:color="?colorPrimary" />
</shape>
</item>
</layer-list>

View File

@@ -1,25 +0,0 @@
<?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/>.
~
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="8dp" />
<solid android:color="@color/colorRedAlt" />
</shape>

View File

@@ -1,27 +0,0 @@
<?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/>.
~
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="15dp" />
<stroke
android:width="1dp"
android:color="?colorControlHighlight" />
</shape>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
</shape>

View File

@@ -1,27 +0,0 @@
<?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/>.
~
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners android:radius="@dimen/radius_large" />
<solid android:color="?android:colorBackground" />
</shape>
</item>
</layer-list>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Disabled -->
<item android:color="@android:color/transparent" android:state_enabled="false"/>
<!-- Selected -->
<item android:color="?attr/colorControlActivated" android:state_selected="true"/>
<item android:color="?attr/colorControlHighlight" android:state_checked="true"/>
<!-- Not selected -->
<item android:color="?android:colorBackground" />
</selector>

View File

@@ -119,8 +119,4 @@
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
<include
android:id="@+id/layout_details_install"
layout="@layout/layout_details_install" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -18,6 +18,7 @@
-->
<RelativeLayout 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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -26,18 +27,35 @@
android:paddingEnd="@dimen/padding_small"
android:paddingBottom="@dimen/padding_small">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/img_icon"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
tools:src="@drawable/bg_placeholder" />
<RelativeLayout
android:id="@+id/img_icon_layout"
android:layout_width="@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"
android:layout_height="@dimen/icon_size"
tools:src="@drawable/bg_placeholder" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progress_download"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:visibility="gone"
app:indicatorSize="@dimen/icon_size_medium"
app:trackThickness="3dp"
tools:progress="40" />
</RelativeLayout>
<TextView
android:id="@+id/txt_line1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_small"
android:layout_toEndOf="@id/img_icon"
android:layout_toEndOf="@id/img_icon_layout"
android:maxLines="2"
android:textAppearance="@style/TextAppearance.Aurora.SubTitle"
tools:text="App Name" />
@@ -84,4 +102,34 @@
android:layout_alignEnd="@id/txt_line1"
android:textAppearance="@style/TextAppearance.Aurora.Line2"
tools:text="Free" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/txt_line4"
android:divider="@drawable/divider"
android:orientation="horizontal"
android:showDividers="middle">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_secondary_action"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_small"
android:layout_weight="1"
android:backgroundTint="?colorError"
android:textColor="?colorOnError"
android:visibility="gone"
tools:text="@string/action_cancel"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_primary_action"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_small"
android:layout_weight="1"
tools:text="@string/action_install" />
</LinearLayout>
</RelativeLayout>

View File

@@ -1,137 +0,0 @@
<?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/>.
~
-->
<LinearLayout 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"
android:id="@+id/bottomSheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_bottomsheet"
android:divider="@drawable/divider"
android:orientation="vertical"
android:paddingStart="@dimen/padding_small"
android:paddingEnd="@dimen/padding_small"
android:showDividers="middle"
app:behavior_hideable="false"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<ViewFlipper
android:id="@+id/view_flipper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateFirstView="true"
android:inAnimation="@anim/fade_in"
android:outAnimation="@anim/fade_out"
tools:ignore="UselessParent">
<com.aurora.store.view.custom.layouts.button.ActionButton
android:id="@+id/btn_download"
android:layout_width="match_parent"
android:layout_height="@dimen/height_button"
android:layout_marginTop="@dimen/margin_xsmall"
android:layout_marginBottom="@dimen/margin_xsmall"
android:text="@string/action_install"
app:btnActionText="@string/action_install"
app:btnActionTextColor="?colorOnPrimary" />
<RelativeLayout
android:id="@+id/progress_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/height_button"
android:layout_marginTop="@dimen/margin_xsmall"
android:layout_marginBottom="@dimen/margin_xsmall"
android:gravity="center_vertical"
android:weightSum="4">
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progress_download"
style="@style/Widget.Material3.LinearProgressIndicator.Legacy"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_toStartOf="@id/img_cancel"
android:background="@drawable/bg_rounded_transparent"
android:indeterminate="true"
android:indeterminateTint="?colorOnPrimary"
app:indicatorColor="?colorControlHighlight"
app:trackColor="?colorPrimary"
app:trackThickness="@dimen/icon_size_small" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toStartOf="@id/img_cancel"
android:gravity="center_vertical"
android:orientation="horizontal"
android:weightSum="3">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/txt_progress_percent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_xsmall"
android:layout_weight="1"
android:paddingStart="@dimen/padding_normal"
android:paddingEnd="@dimen/padding_normal"
android:text="0%"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.Aurora.Title"
android:textColor="?colorOnPrimary"
android:textSize="32sp" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_small"
android:layout_weight="2"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/txt_speed"
style="@style/TextAppearance.Aurora.Line1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/download_speed_estimating"
android:textColor="?colorOnPrimary" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/txt_eta"
style="@style/TextAppearance.Aurora.Line2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/download_eta_calculating"
android:textColor="?colorOnPrimary" />
</LinearLayout>
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/img_cancel"
android:layout_width="@dimen/icon_size_small"
android:layout_height="@dimen/icon_size_small"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginStart="@dimen/margin_small"
android:background="@drawable/bg_cancel"
android:padding="@dimen/padding_medium"
android:tint="@color/colorWhite"
app:srcCompat="@drawable/ic_cancel" />
</RelativeLayout>
</ViewFlipper>
</LinearLayout>

View File

@@ -1,68 +0,0 @@
<?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:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="@dimen/height_button">
<ViewFlipper
android:id="@+id/view_flipper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateFirstView="true"
android:inAnimation="@anim/fade_in"
android:outAnimation="@anim/fade_out"
tools:ignore="UselessParent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn"
style="@style/Widget.Material3.Button.TextButton.Dialog.Flush"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:textAllCaps="true"
android:textAppearance="@style/TextAppearance.Aurora.SubTitle"
app:iconPadding="@dimen/padding_large"
tools:text="Install" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
app:srcCompat="@drawable/ic_check"
app:tint="@color/colorWhite" />
</RelativeLayout>
</ViewFlipper>
</RelativeLayout>

View File

@@ -28,12 +28,6 @@
<attr name="btnStateIcon" format="reference" />
</declare-styleable>
<declare-styleable name="ActionButton">
<attr name="btnActionText" format="string" />
<attr name="btnActionTextColor" format="string" />
<attr name="btnActionIcon" format="string" />
</declare-styleable>
<declare-styleable name="AuroraProgressView">
<attr name="minWidth" format="dimension" />
<attr name="maxWidth" format="dimension" />
@@ -48,4 +42,4 @@
<attr name="txtSubtitle" format="string" />
<attr name="imgIcon" format="reference" />
</declare-styleable>
</resources>
</resources>