diff --git a/app/src/main/java/com/aurora/extensions/Commons.kt b/app/src/main/java/com/aurora/extensions/Commons.kt index af88aebbf..90c2b48a4 100644 --- a/app/src/main/java/com/aurora/extensions/Commons.kt +++ b/app/src/main/java/com/aurora/extensions/Commons.kt @@ -19,11 +19,14 @@ package com.aurora.extensions +import android.graphics.Color import android.text.format.DateFormat +import androidx.annotation.ColorInt import java.io.PrintWriter import java.io.StringWriter import java.util.Calendar import java.util.Locale +import javax.annotation.Nullable fun Long.toDate(): String { val calendar = Calendar.getInstance(Locale.getDefault()) @@ -42,4 +45,51 @@ fun Throwable.stackTraceToString(): String { fun isValidPackageName(packageName: String): Boolean { val packageRegex = "^[a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*)*$".toRegex() return packageName.matches(packageRegex) +} + +/** + * Computes a darker color from the given color. + * @param color The color to darken. + * @param factor The factor to darken the color by. + * - higher factor values will result in a lighter color. + * @return The darker color. + */ +fun darkenColor(@ColorInt color: Int, factor: Float = 0.25f): Int { + val a = Color.alpha(color) + val r = (Color.red(color) * factor).coerceIn(0f, 255f).toInt() + val g = (Color.green(color) * factor).coerceIn(0f, 255f).toInt() + val b = (Color.blue(color) * factor).coerceIn(0f, 255f).toInt() + + return Color.argb(a, r, g, b) +} + +/** + * Computes a lighter color from the given color. + * @param color The color to lighten. + * @param factor The factor to lighten the color by. + * - higher factor values will result in a lighter color. + * @param alpha The alpha value to use for the lighter color. + * @return The lighter color. + */ +fun lightenColor(@ColorInt color: Int, factor: Float = 0.5f, @Nullable alpha: Int? = null): Int { + val a = alpha ?: Color.alpha(color) + val r = (Color.red(color) + (255 - Color.red(color)) * factor).toInt() + val g = (Color.green(color) + (255 - Color.green(color)) * factor).toInt() + val b = (Color.blue(color) + (255 - Color.blue(color)) * factor).toInt() + + return Color.argb(a, r, g, b) +} + +/** + * Computes a contrasting color from the given color. + * @param color The color to contrast. + * @return The contrasting color. + */ +fun contrastingColor(@ColorInt color: Int): Int { + val red = Color.red(color) + val green = Color.green(color) + val blue = Color.blue(color) + val yiq = ((red * 299) + (green * 587) + (blue * 114)) / 1000 + + return if (yiq >= 128) Color.BLACK else Color.WHITE } \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/custom/layouts/DevInfoLayout.kt b/app/src/main/java/com/aurora/store/view/custom/layouts/DevInfoLayout.kt index 1c3c69124..4ce3fcbe1 100644 --- a/app/src/main/java/com/aurora/store/view/custom/layouts/DevInfoLayout.kt +++ b/app/src/main/java/com/aurora/store/view/custom/layouts/DevInfoLayout.kt @@ -22,6 +22,8 @@ package com.aurora.store.view.custom.layouts import android.content.Context import android.util.AttributeSet import android.widget.RelativeLayout +import androidx.appcompat.widget.AppCompatImageView +import androidx.core.view.isVisible import com.aurora.store.R import com.aurora.store.databinding.ViewDevInfoBinding @@ -29,6 +31,16 @@ class DevInfoLayout : RelativeLayout { private lateinit var binding: ViewDevInfoBinding + val icon: AppCompatImageView get() = binding.img + + var title: String + get() = binding.txtTitle.text.toString() + set(value) = setTxtTitle(value) + + var subTitle: String? + get() = binding.txtSubtitle.text.toString() + set(value) = setTxtSubtitle(value) + constructor(context: Context) : super(context) { init(context, null) } @@ -64,8 +76,15 @@ class DevInfoLayout : RelativeLayout { typedArray.recycle() } + fun setTxtTitle(text: String?) { + binding.txtTitle.text = text + binding.txtTitle.isVisible = text != null + invalidate() + } + fun setTxtSubtitle(text: String?) { binding.txtSubtitle.text = text + binding.txtSubtitle.isVisible = text != null invalidate() } } diff --git a/app/src/main/java/com/aurora/store/view/custom/layouts/button/UpdateButton.kt b/app/src/main/java/com/aurora/store/view/custom/layouts/button/UpdateButton.kt index 49ba8a8fe..95a7dcff3 100644 --- a/app/src/main/java/com/aurora/store/view/custom/layouts/button/UpdateButton.kt +++ b/app/src/main/java/com/aurora/store/view/custom/layouts/button/UpdateButton.kt @@ -20,9 +20,13 @@ 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 com.aurora.extensions.accentColor +import com.aurora.extensions.darkenColor import com.aurora.extensions.getString +import com.aurora.extensions.lightenColor import com.aurora.extensions.runOnUiThread import com.aurora.store.R import com.aurora.store.data.model.DownloadStatus @@ -51,6 +55,15 @@ class UpdateButton : RelativeLayout { private fun init(context: Context) { val view = inflate(context, R.layout.view_update_button, this) binding = ViewUpdateButtonBinding.bind(view) + + // Apply primaryColor tint to all buttons with alpha + val alphaAccent = lightenColor(context.accentColor(), alpha = 200) + binding.btnPositive.backgroundTintList = ColorStateList.valueOf(alphaAccent) + binding.btnNegative.backgroundTintList = ColorStateList.valueOf(alphaAccent) + + val textColor = darkenColor(context.accentColor()) + binding.btnPositive.setTextColor(textColor) + binding.btnNegative.setTextColor(textColor) } fun setText(text: String) { @@ -65,9 +78,8 @@ class UpdateButton : RelativeLayout { fun updateState(downloadStatus: DownloadStatus) { val displayChild = when (downloadStatus) { - DownloadStatus.QUEUED, + DownloadStatus.QUEUED -> 1 DownloadStatus.DOWNLOADING -> 2 - else -> 0 } diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/UpdateHeaderView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/UpdateHeaderView.kt index 8faaf1a90..0452a4ebd 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/views/UpdateHeaderView.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/UpdateHeaderView.kt @@ -25,6 +25,8 @@ import com.airbnb.epoxy.CallbackProp import com.airbnb.epoxy.ModelProp import com.airbnb.epoxy.ModelView import com.airbnb.epoxy.OnViewRecycled +import com.aurora.extensions.accentColor +import com.aurora.extensions.contrastingColor import com.aurora.store.databinding.ViewHeaderUpdateBinding @@ -46,6 +48,7 @@ class UpdateHeaderView @JvmOverloads constructor( @ModelProp fun action(action: String) { binding.btnAction.text = action + binding.btnAction.setTextColor(contrastingColor(context.accentColor())) } @CallbackProp diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/app/NoAppView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/app/NoAppView.kt index 9b563075f..65e25dddd 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/views/app/NoAppView.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/app/NoAppView.kt @@ -26,6 +26,8 @@ import androidx.core.view.isVisible import com.airbnb.epoxy.CallbackProp import com.airbnb.epoxy.ModelProp import com.airbnb.epoxy.ModelView +import com.aurora.extensions.accentColor +import com.aurora.extensions.contrastingColor import com.aurora.store.databinding.ViewNoAppBinding import com.aurora.store.view.epoxy.views.BaseModel import com.aurora.store.view.epoxy.views.BaseView @@ -62,6 +64,7 @@ class NoAppView @JvmOverloads constructor( @ModelProp fun actionMessage(message: String = String()) { binding.button.text = message + binding.button.setTextColor(contrastingColor(context.accentColor())) } @JvmOverloads diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/MoreDialogFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/MoreDialogFragment.kt index dbae37a26..ae7af532b 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/MoreDialogFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/MoreDialogFragment.kt @@ -6,6 +6,7 @@ import android.os.Bundle import androidx.annotation.DrawableRes import androidx.annotation.IdRes import androidx.annotation.StringRes +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -33,6 +34,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext @@ -50,7 +52,11 @@ import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest import com.aurora.Constants import com.aurora.Constants.URL_TOS +import com.aurora.extensions.accentColor import com.aurora.extensions.browse +import com.aurora.extensions.darkenColor +import com.aurora.extensions.getStyledAttributeColor +import com.aurora.extensions.lightenColor import com.aurora.store.R import com.aurora.store.data.providers.AuthProvider import com.aurora.store.view.theme.AuroraTheme @@ -64,6 +70,11 @@ class MoreDialogFragment : DialogFragment() { @Inject lateinit var authProvider: AuthProvider + private var primaryColor: Color = Color.White + private var onPrimaryColor: Color = Color.Black + private var secondaryColor: Color = Color.White + private var onSecondaryColor: Color = Color.Black + private data class Option( @StringRes val title: Int, @DrawableRes val icon: Int, @@ -81,30 +92,37 @@ class MoreDialogFragment : DialogFragment() { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { AuroraTheme { - val backgroundColor = if (isSystemInDarkTheme()) { - MaterialTheme.colorScheme.onSecondary + if (isSystemInDarkTheme()) { + primaryColor = Color(darkenColor(requireContext().accentColor(), 0.25f)) + onPrimaryColor = Color(lightenColor(primaryColor.toArgb())) + secondaryColor = Color(darkenColor(requireContext().accentColor(), 0.15f)) + onSecondaryColor = Color(lightenColor(primaryColor.toArgb())) } else { - MaterialTheme.colorScheme.surfaceVariant + primaryColor = Color(lightenColor(requireContext().accentColor(), 0.85f)) + onPrimaryColor = Color(darkenColor(primaryColor.toArgb())) + secondaryColor = Color(lightenColor(requireContext().accentColor(), 0.95f)) + onSecondaryColor = Color(darkenColor(primaryColor.toArgb())) } - val onBackgroundColor = if (isSystemInDarkTheme()) { - MaterialTheme.colorScheme.onSurface - } else { - MaterialTheme.colorScheme.onSecondary - } - - val tintColor = if (isSystemInDarkTheme()) Color.White else Color.Black - Column( modifier = Modifier .fillMaxWidth() - .background(color = backgroundColor) + .background(color = primaryColor) .verticalScroll(rememberScrollState()) .padding(10.dp), - verticalArrangement = Arrangement.spacedBy(5.dp, Alignment.CenterVertically) + verticalArrangement = Arrangement.spacedBy( + 5.dp, + Alignment.CenterVertically + ) ) { - AppBar(tintColor = tintColor) - AccountHeader(backgroundColor = onBackgroundColor) + AppBar( + backgroundColor = primaryColor, + onBackgroundColor = onPrimaryColor + ) + AccountHeader( + backgroundColor = secondaryColor, + onBackgroundColor = onSecondaryColor + ) Column( modifier = Modifier .clip( @@ -115,17 +133,22 @@ class MoreDialogFragment : DialogFragment() { bottomEnd = 20.dp ) ) - .background(color = onBackgroundColor) + .background(color = secondaryColor) ) { - getOptions().fastForEach { option -> OptionItem(option = option) } + getOptions().fastForEach { option -> + OptionItem( + option = option, + tintColor = onSecondaryColor + ) + } } getExtraOptions().fastForEach { option -> OptionItem( option = option, - tintColor = tintColor + tintColor = onPrimaryColor ) } - Footer(tintColor) + Footer(onPrimaryColor) } } } @@ -133,20 +156,20 @@ class MoreDialogFragment : DialogFragment() { } @Composable - fun AppBar(tintColor: Color) { + fun AppBar(backgroundColor: Color = Color.Transparent, onBackgroundColor: Color) { Box(contentAlignment = Alignment.CenterEnd) { Text( modifier = Modifier.fillMaxWidth(), text = stringResource(id = R.string.app_name), style = MaterialTheme.typography.titleMedium, - color = tintColor, + color = onBackgroundColor, textAlign = TextAlign.Center ) IconButton(onClick = { findNavController().navigateUp() }) { Icon( painter = painterResource(id = R.drawable.ic_cancel), contentDescription = stringResource(id = R.string.action_cancel), - tint = tintColor + tint = onBackgroundColor ) } } @@ -157,11 +180,12 @@ class MoreDialogFragment : DialogFragment() { Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(5.dp, Alignment.CenterHorizontally) + horizontalArrangement = Arrangement.spacedBy(2.dp, Alignment.CenterHorizontally) ) { TextButton(onClick = { requireContext().browse(Constants.URL_POLICY) }) { Text( text = stringResource(id = R.string.privacy_policy_title), + fontWeight = FontWeight.Light, color = tintColor ) } @@ -169,6 +193,7 @@ class MoreDialogFragment : DialogFragment() { TextButton(onClick = { requireContext().browse(URL_TOS) }) { Text( text = stringResource(id = R.string.menu_terms), + fontWeight = FontWeight.Light, color = tintColor ) } @@ -176,13 +201,16 @@ class MoreDialogFragment : DialogFragment() { } @Composable - private fun AccountHeader(backgroundColor: Color) { + private fun AccountHeader(backgroundColor: Color, onBackgroundColor: Color = Color.White) { Column( modifier = Modifier .fillMaxWidth() .clip( RoundedCornerShape( - topStart = 20.dp, topEnd = 20.dp, bottomStart = 5.dp, bottomEnd = 5.dp + topStart = 20.dp, + topEnd = 20.dp, + bottomStart = 5.dp, + bottomEnd = 5.dp ) ) .background(color = backgroundColor) @@ -205,7 +233,7 @@ class MoreDialogFragment : DialogFragment() { contentDescription = stringResource(id = R.string.title_account_manager), contentScale = ContentScale.Crop, modifier = Modifier - .requiredSize(48.dp) + .requiredSize(36.dp) .clip(CircleShape) ) Column( @@ -213,24 +241,32 @@ class MoreDialogFragment : DialogFragment() { horizontalAlignment = Alignment.Start ) { Text( - text = if (authProvider.isAnonymous) "anonymous" else authProvider.authData!!.userProfile!!.name, - fontWeight = FontWeight.SemiBold, - fontSize = 16.sp + text = if (authProvider.isAnonymous) "Anonymous" else authProvider.authData!!.userProfile!!.name, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + color = onBackgroundColor ) Text( text = if (authProvider.isAnonymous) "anonymous@gmail.com" else authProvider.authData!!.userProfile!!.email, - fontWeight = FontWeight.Normal, - fontSize = 14.sp + fontWeight = FontWeight.Light, + fontSize = 14.sp, + color = onBackgroundColor ) } } OutlinedButton( onClick = { findNavController().navigate(R.id.accountFragment) }, - shape = RoundedCornerShape(12.dp) + shape = RoundedCornerShape(12.dp), + border = BorderStroke( + 1.dp, + Color(requireContext().getStyledAttributeColor(androidx.appcompat.R.attr.colorControlHighlight)) + ), + modifier = Modifier.fillMaxWidth() ) { Text( text = stringResource(id = R.string.manage_account), - color = Color.Black + color = onBackgroundColor, + fontWeight = FontWeight.Medium ) } } diff --git a/app/src/main/java/com/aurora/store/view/ui/details/AppDetailsFragment.kt b/app/src/main/java/com/aurora/store/view/ui/details/AppDetailsFragment.kt index 6d4210741..366ab07fc 100644 --- a/app/src/main/java/com/aurora/store/view/ui/details/AppDetailsFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/details/AppDetailsFragment.kt @@ -39,7 +39,9 @@ import coil.load import coil.transform.RoundedCornersTransformation import com.aurora.Constants import com.aurora.Constants.EXODUS_SUBMIT_PAGE +import com.aurora.extensions.accentColor import com.aurora.extensions.browse +import com.aurora.extensions.contrastingColor import com.aurora.extensions.getString import com.aurora.extensions.hide import com.aurora.extensions.runOnUiThread @@ -51,6 +53,7 @@ import com.aurora.gplayapi.data.models.File import com.aurora.gplayapi.data.models.Review import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.gplayapi.data.models.datasafety.EntryType import com.aurora.store.AppStreamStash import com.aurora.store.AuroraApp import com.aurora.store.PermissionType @@ -89,6 +92,7 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import java.util.Locale import javax.inject.Inject +import com.aurora.gplayapi.data.models.datasafety.Report as DataSafetyReport @AndroidEntryPoint class AppDetailsFragment : BaseFragment() { @@ -264,6 +268,11 @@ class AppDetailsFragment : BaseFragment() { } } + // Data Safety Report + viewLifecycleOwner.lifecycleScope.launch { + viewModel.dataSafetyReport.collect { updateDataSafetyViews(it) } + } + // Exodus Privacy Report viewLifecycleOwner.lifecycleScope.launch { viewModel.exodusReport.collect { report -> @@ -310,7 +319,10 @@ class AppDetailsFragment : BaseFragment() { viewLifecycleOwner.lifecycleScope.launch { viewModel.testingProgramStatus.collect { if (it != null) { - binding.layoutDetailsBeta.btnBetaAction.isEnabled = true + binding.layoutDetailsBeta.btnBetaAction.apply { + isEnabled = true + setTextColor(contrastingColor(requireContext().accentColor())) + } if (it.subscribed) { updateBetaActions(true) } @@ -342,8 +354,11 @@ class AppDetailsFragment : BaseFragment() { } // Misc Bindings - binding.layoutDetailsPrivacy.btnRequestAnalysis.setOnClickListener { - it.context.browse("${EXODUS_SUBMIT_PAGE}${app.packageName}") + binding.layoutDetailsPrivacy.btnRequestAnalysis.apply { + setOnClickListener { + it.context.browse("${EXODUS_SUBMIT_PAGE}${app.packageName}") + } + setTextColor(contrastingColor(requireContext().accentColor())) } binding.layoutDetailsInstall.progressDownload.clipToOutline = true binding.layoutDetailsInstall.imgCancel.setOnClickListener { @@ -687,6 +702,7 @@ class AppDetailsFragment : BaseFragment() { inflateAppDescription(app) inflateAppRatingAndReviews(app) inflateAppDevInfo(app) + inflateAppDataSafety(app) inflateAppPrivacy(app) inflateAppPermission(app) @@ -814,6 +830,10 @@ class AppDetailsFragment : BaseFragment() { } } + private fun inflateAppDataSafety(app: App) { + viewModel.fetchAppDataSafetyReport(app.packageName) + } + private fun inflateAppPrivacy(app: App) { viewModel.fetchAppReport(app.packageName) } @@ -953,6 +973,32 @@ class AppDetailsFragment : BaseFragment() { } } + private fun updateDataSafetyViews(report: DataSafetyReport) { + report.entries.groupBy { it.type }.forEach { (type, entries) -> + when (type) { + EntryType.DATA_COLLECTED -> { + binding.layoutDetailsDataSafety.dataCollect.title = HtmlCompat.fromHtml( + entries.first().description, + HtmlCompat.FROM_HTML_MODE_COMPACT + ).toString() + binding.layoutDetailsDataSafety.dataCollect.subTitle = + entries.first().subEntries.joinToString(", ") { it.name }.ifBlank { null } + } + + EntryType.DATA_SHARED -> { + binding.layoutDetailsDataSafety.dataShare.title = HtmlCompat.fromHtml( + entries.first().description, + HtmlCompat.FROM_HTML_MODE_COMPACT + ).toString() + binding.layoutDetailsDataSafety.dataShare.subTitle = + entries.first().subEntries.joinToString(", ") { it.name }.ifBlank { null } + } + + else -> {} + } + } + } + /* App Review Helpers */ private fun addAvgReviews(number: Int, max: Long, rating: Long): RelativeLayout { diff --git a/app/src/main/java/com/aurora/store/viewmodel/details/AppDetailsViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/details/AppDetailsViewModel.kt index 54b2c67b2..af1737e07 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/details/AppDetailsViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/details/AppDetailsViewModel.kt @@ -9,6 +9,7 @@ import com.aurora.gplayapi.data.models.Review import com.aurora.gplayapi.data.models.details.TestingProgramStatus import com.aurora.gplayapi.helpers.AppDetailsHelper import com.aurora.gplayapi.helpers.ReviewsHelper +import com.aurora.gplayapi.helpers.web.WebDataSafetyHelper import com.aurora.store.data.model.ExodusReport import com.aurora.store.data.model.Report import com.aurora.store.data.network.HttpClient @@ -28,6 +29,7 @@ import kotlinx.coroutines.launch import org.json.JSONObject import java.lang.reflect.Modifier import javax.inject.Inject +import com.aurora.gplayapi.data.models.datasafety.Report as DataSafetyReport @HiltViewModel class AppDetailsViewModel @Inject constructor( @@ -58,6 +60,10 @@ class AppDetailsViewModel @Inject constructor( private val _userReview = MutableSharedFlow() val userReview = _userReview.asSharedFlow() + private val dataSafetyReportStash = mutableMapOf() + private val _dataSafetyReport = MutableSharedFlow() + val dataSafetyReport = _dataSafetyReport.asSharedFlow() + private val exodusReportStash = mutableMapOf() private val _exodusReport = MutableSharedFlow() val exodusReport = _exodusReport.asSharedFlow() @@ -103,6 +109,21 @@ class AppDetailsViewModel @Inject constructor( } } + fun fetchAppDataSafetyReport(packageName: String) { + viewModelScope.launch(Dispatchers.IO) { + try { + val report = dataSafetyReportStash.getOrPut(packageName) { + WebDataSafetyHelper() + .using(httpClient) + .fetch(packageName) + } + _dataSafetyReport.emit(report) + } catch (exception: Exception) { + Log.e(TAG, "Failed to fetch data safety report", exception) + } + } + } + fun fetchAppReport(packageName: String) { viewModelScope.launch(Dispatchers.IO) { try { diff --git a/app/src/main/res/drawable/ic_cloud_upload.xml b/app/src/main/res/drawable/ic_cloud_upload.xml new file mode 100644 index 000000000..ecf35e1d8 --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_upload.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml index ae87ad01b..77ae231ef 100644 --- a/app/src/main/res/layout/fragment_details.xml +++ b/app/src/main/res/layout/fragment_details.xml @@ -103,6 +103,10 @@ android:id="@+id/layout_details_permissions" layout="@layout/layout_details_permissions" /> + + diff --git a/app/src/main/res/layout/layout_details_data_safety.xml b/app/src/main/res/layout/layout_details_data_safety.xml new file mode 100644 index 000000000..4caabe496 --- /dev/null +++ b/app/src/main/res/layout/layout_details_data_safety.xml @@ -0,0 +1,35 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/view_app_update.xml b/app/src/main/res/layout/view_app_update.xml index 04368ff7b..8e421cd53 100644 --- a/app/src/main/res/layout/view_app_update.xml +++ b/app/src/main/res/layout/view_app_update.xml @@ -106,6 +106,7 @@ android:layout_alignTop="@id/txt_line1" android:layout_toStartOf="@id/btn_action" android:contentDescription="@string/details_changelog" + app:iconTint="?colorControlNormal" app:icon="@drawable/ic_arrow_down" /> + android:text="@string/action_update_all" + android:textAppearance="@style/TextAppearance.Aurora.Line1" /> diff --git a/app/src/main/res/layout/view_no_app.xml b/app/src/main/res/layout/view_no_app.xml index b30269ada..c3c1aee25 100644 --- a/app/src/main/res/layout/view_no_app.xml +++ b/app/src/main/res/layout/view_no_app.xml @@ -41,12 +41,13 @@ android:textAppearance="@style/TextAppearance.Aurora.Line1" tools:text="No updates available" /> -