AppDetails: Fix user review + minor cleanup

This commit is contained in:
Rahul Patel
2024-12-14 23:29:02 +05:30
parent d2145962d8
commit c7fefb12c7
8 changed files with 193 additions and 167 deletions

View File

@@ -87,7 +87,8 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true"> android:exported="true"
android:windowSoftInputMode="adjustPan">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@@ -188,18 +188,18 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
if (args.app != null) { app = args.app ?: App(args.packageName)
app = args.app!! app.apply {
inflatePartialApp() // Check whether app is installed or not
} else { isInstalled = PackageUtil.isInstalled(requireContext(), app.packageName)
app = App(args.packageName) uninstallActionEnabled = isInstalled
} }
// Toolbar // Show the basic app details, while the rest of the data is being fetched
attachToolbar() updateAppHeader(app)
// Check whether app is installed or not // Toolbar
app.isInstalled = PackageUtil.isInstalled(requireContext(), app.packageName) attachToolbar(app)
// App Details // App Details
viewModel.fetchAppDetails(app.packageName) viewModel.fetchAppDetails(app.packageName)
@@ -208,11 +208,27 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
viewModel.app.collect { viewModel.app.collect {
if (it.packageName.isNotBlank()) { if (it.packageName.isNotBlank()) {
app = it app = it
inflatePartialApp() // Re-inflate the app details, as web data may vary.
inflateExtraDetails(app) // App User Review
// We can not fetch it outside of this block, as we need the testing program status
if (!authProvider.isAnonymous && app.isInstalled) {
viewModel.fetchUserAppReview(app)
}
updateAppHeader(app) // Re-inflate the app details, as web data may vary.
updateExtraDetails(app)
// Fetch App Reviews
viewModel.fetchAppReviews(app.packageName) viewModel.fetchAppReviews(app.packageName)
// Fetch Data Safety Report
viewModel.fetchAppDataSafetyReport(app.packageName)
// Fetch Exodus Privacy Report
viewModel.fetchAppReport(app.packageName)
} else { } else {
toast("Failed to fetch app details") toast(getString(R.string.status_unavailable))
// TODO: Redirect to App Unavailable Fragment
} }
} }
} }
@@ -257,12 +273,7 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
viewModel.userReview.collect { viewModel.userReview.collect {
if (it.commentId.isNotEmpty()) { if (it.commentId.isNotEmpty()) {
binding.layoutDetailsReview.userStars.rating = it.rating.toFloat() runOnUiThread { updateUserReview(it) }
Toast.makeText(
requireContext(),
getString(R.string.toast_rated_success),
Toast.LENGTH_SHORT
).show()
} else { } else {
Toast.makeText( Toast.makeText(
requireContext(), requireContext(),
@@ -377,10 +388,11 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
super.onResume() super.onResume()
} }
private fun attachToolbar() { private fun attachToolbar(app: App) {
binding.layoutDetailsToolbar.toolbar.apply { binding.layoutDetailsToolbar.toolbar.apply {
elevation = 0f elevation = 0f
navigationIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_arrow_back) navigationIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_arrow_back)
setNavigationOnClickListener { setNavigationOnClickListener {
if (isExternal) { if (isExternal) {
activity?.finish() activity?.finish()
@@ -389,8 +401,22 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
} }
} }
// Inflate Menu
inflateMenu(R.menu.menu_details) inflateMenu(R.menu.menu_details)
// Adjust Menu Items
menu.let {
it.findItem(R.id.action_home_screen)?.isVisible =
app.isInstalled && ShortcutManagerUtil.canPinShortcut(
requireContext(),
app.packageName
)
it.findItem(R.id.menu_download_manual)?.isVisible = !app.isInstalled
it.findItem(R.id.action_uninstall)?.isVisible = app.isInstalled
it.findItem(R.id.menu_app_settings)?.isVisible = app.isInstalled
}
// Set Menu Item Clicks
setOnMenuItemClickListener { setOnMenuItemClickListener {
when (it.itemId) { when (it.itemId) {
R.id.action_home_screen -> { R.id.action_home_screen -> {
@@ -436,26 +462,13 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
requireContext().browse("${Constants.SHARE_URL}${app.packageName}") requireContext().browse("${Constants.SHARE_URL}${app.packageName}")
} }
} }
true true
} }
if (::app.isInitialized) {
app.isInstalled = PackageUtil.isInstalled(requireContext(), app.packageName)
menu?.findItem(R.id.action_home_screen)?.isVisible =
app.isInstalled && ShortcutManagerUtil.canPinShortcut(
requireContext(),
app.packageName
)
menu?.findItem(R.id.action_uninstall)?.isVisible = app.isInstalled
menu?.findItem(R.id.menu_app_settings)?.isVisible = app.isInstalled
uninstallActionEnabled = app.isInstalled
}
} }
} }
private fun attachHeader() { private fun updateAppHeader(app: App) {
binding.layoutDetailsApp.apply { binding.layoutDetailsApp.apply {
imgIcon.load(app.iconArtwork.url) { imgIcon.load(app.iconArtwork.url) {
placeholder(R.drawable.bg_placeholder) placeholder(R.drawable.bg_placeholder)
@@ -465,27 +478,20 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
} }
} }
packageName.text = app.packageName
txtLine1.text = app.displayName txtLine1.text = app.displayName
txtLine2.text = app.developerName txtLine2.text = app.developerName
txtLine3.text = ("${app.versionName} (${app.versionCode})")
txtLine2.setOnClickListener { txtLine2.setOnClickListener {
findNavController().navigate( findNavController().navigate(
AppDetailsFragmentDirections AppDetailsFragmentDirections
.actionAppDetailsFragmentToDevAppsFragment(app.developerName) .actionAppDetailsFragmentToDevAppsFragment(app.developerName)
) )
} }
txtLine3.text = ("${app.versionName} (${app.versionCode})")
packageName.text = app.packageName
tags.add(getString((if (app.isFree) R.string.details_free else R.string.details_paid)))
if (app.isFree) tags.add(getString((if (app.containsAds) R.string.details_contains_ads else R.string.details_no_ads)))
tags.add(getString(R.string.details_free))
else
tags.add(getString(R.string.details_paid))
if (app.containsAds)
tags.add(getString(R.string.details_contains_ads))
else
tags.add(getString(R.string.details_no_ads))
txtLine4.text = tags.joinToString(separator = "") txtLine4.text = tags.joinToString(separator = "")
} }
@@ -724,40 +730,34 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
} }
} }
private fun inflatePartialApp() { private fun updateExtraDetails(app: App) {
if (::app.isInitialized) { binding.viewFlipper.displayedChild = 1
attachHeader()
checkAndSetupInstall()
}
}
private fun inflateExtraDetails(app: App?) { updateAppDescription(app)
app?.let { updateAppRatingAndReviews(app)
binding.viewFlipper.displayedChild = 1 updateAppDevInfo(app)
inflateAppDescription(app) updateAppPermission(app)
inflateAppRatingAndReviews(app)
inflateAppDevInfo(app)
inflateAppDataSafety(app)
inflateAppPrivacy(app)
inflateAppPermission(app)
if (!authProvider.isAnonymous) { // Allow users to handle beta subscriptions, if logged in by own account.
app.testingProgram?.let { if (!authProvider.isAnonymous) {
if (it.isAvailable && it.isSubscribed) { // Update app name to the testing program name, if subscribed
binding.layoutDetailsApp.txtLine1.text = it.displayName app.testingProgram?.let {
} if (it.isAvailable && it.isSubscribed) {
binding.layoutDetailsApp.txtLine1.text = it.displayName
} }
inflateBetaSubscription(app)
} }
if (showSimilarApps) { updateBetaSubscription(app)
inflateAppStream(app)
}
} }
if (showSimilarApps) {
updateAppStream(app)
}
checkAndSetupInstall()
} }
private fun inflateAppDescription(app: App) { private fun updateAppDescription(app: App) {
binding.layoutDetailDescription.apply { binding.layoutDetailDescription.apply {
val installs = CommonUtil.addDiPrefix(app.installs) val installs = CommonUtil.addDiPrefix(app.installs)
@@ -814,10 +814,16 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
} }
} }
private fun inflateAppRatingAndReviews(app: App) { private fun updateAppRatingAndReviews(app: App) {
binding.layoutDetailsReview.apply { binding.layoutDetailsReview.apply {
averageRating.text = app.rating.average.toString() headerRatingReviews.addClickListener {
txtReviewCount.text = app.rating.abbreviatedLabel findNavController().navigate(
AppDetailsFragmentDirections.actionAppDetailsFragmentToDetailsReviewFragment(
app.displayName,
app.packageName
)
)
}
var totalStars = 0L var totalStars = 0L
totalStars += app.rating.oneStar totalStars += app.rating.oneStar
@@ -837,42 +843,34 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
averageRating.text = String.format(Locale.getDefault(), "%.1f", app.rating.average) averageRating.text = String.format(Locale.getDefault(), "%.1f", app.rating.average)
txtReviewCount.text = app.rating.abbreviatedLabel txtReviewCount.text = app.rating.abbreviatedLabel
}
}
layoutUserReview.visibility = private fun updateUserReview(review: Review) {
if (authProvider.isAnonymous) View.GONE else View.VISIBLE binding.layoutDetailsReview.apply {
layoutUserReview.visibility = View.VISIBLE
inputTitle.setText(review.title)
inputReview.setText(review.comment)
userStars.rating = review.rating.toFloat()
btnPostReview.setOnClickListener { if (!authProvider.isAnonymous && app.isInstalled) {
if (authProvider.isAnonymous) { btnPostReview.setOnClickListener {
toast(R.string.toast_anonymous_restriction) addOrUpdateReview(
} else { app,
addOrUpdateReview(app, Review().apply { Review().apply {
title = inputTitle.text.toString() title = inputTitle.text.toString()
rating = userStars.rating.toInt() rating = userStars.rating.toInt()
comment = inputReview.text.toString() comment = inputReview.text.toString()
}) }
}
}
headerRatingReviews.addClickListener {
findNavController().navigate(
AppDetailsFragmentDirections.actionAppDetailsFragmentToDetailsReviewFragment(
app.displayName,
app.packageName
) )
) }
} else {
layoutUserReview.visibility = View.GONE
} }
} }
} }
private fun inflateAppDataSafety(app: App) { private fun updateAppDevInfo(app: App) {
viewModel.fetchAppDataSafetyReport(app.packageName)
}
private fun inflateAppPrivacy(app: App) {
viewModel.fetchAppReport(app.packageName)
}
private fun inflateAppDevInfo(app: App) {
binding.layoutDetailsDev.apply { binding.layoutDetailsDev.apply {
if (app.developerAddress.isNotEmpty()) { if (app.developerAddress.isNotEmpty()) {
devAddress.apply { devAddress.apply {
@@ -902,7 +900,7 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
} }
} }
private fun inflateBetaSubscription(app: App) { private fun updateBetaSubscription(app: App) {
binding.layoutDetailsBeta.apply { binding.layoutDetailsBeta.apply {
app.testingProgram?.let { betaProgram -> app.testingProgram?.let { betaProgram ->
if (betaProgram.isAvailable) { if (betaProgram.isAvailable) {
@@ -933,7 +931,7 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
} }
} }
private fun inflateAppStream(app: App) { private fun updateAppStream(app: App) {
app.detailsStreamUrl?.let { app.detailsStreamUrl?.let {
val carouselController = val carouselController =
DetailsCarouselController(object : GenericCarouselController.Callbacks { DetailsCarouselController(object : GenericCarouselController.Callbacks {
@@ -980,7 +978,7 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
} }
} }
private fun inflateAppPermission(app: App) { private fun updateAppPermission(app: App) {
binding.layoutDetailsPermissions.apply { binding.layoutDetailsPermissions.apply {
headerPermission.addClickListener { headerPermission.addClickListener {
if (app.permissions.isNotEmpty()) { if (app.permissions.isNotEmpty()) {

View File

@@ -1,9 +1,11 @@
package com.aurora.store.viewmodel.details package com.aurora.store.viewmodel.details
import android.content.Context
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
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.Review import com.aurora.gplayapi.data.models.Review
import com.aurora.gplayapi.data.models.details.TestingProgramStatus import com.aurora.gplayapi.data.models.details.TestingProgramStatus
@@ -12,13 +14,16 @@ import com.aurora.gplayapi.helpers.ReviewsHelper
import com.aurora.gplayapi.helpers.web.WebDataSafetyHelper import com.aurora.gplayapi.helpers.web.WebDataSafetyHelper
import com.aurora.gplayapi.network.IHttpClient import com.aurora.gplayapi.network.IHttpClient
import com.aurora.store.BuildConfig import com.aurora.store.BuildConfig
import com.aurora.store.R
import com.aurora.store.data.helper.DownloadHelper import com.aurora.store.data.helper.DownloadHelper
import com.aurora.store.data.model.ExodusReport import com.aurora.store.data.model.ExodusReport
import com.aurora.store.data.model.Report import com.aurora.store.data.model.Report
import com.aurora.store.data.room.favourite.Favourite import com.aurora.store.data.room.favourite.Favourite
import com.aurora.store.data.room.favourite.FavouriteDao import com.aurora.store.data.room.favourite.FavouriteDao
import com.aurora.store.util.PackageUtil
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -32,6 +37,7 @@ import com.aurora.gplayapi.data.models.datasafety.Report as DataSafetyReport
@HiltViewModel @HiltViewModel
class AppDetailsViewModel @Inject constructor( class AppDetailsViewModel @Inject constructor(
@ApplicationContext private val context: Context,
private val appDetailsHelper: AppDetailsHelper, private val appDetailsHelper: AppDetailsHelper,
private val reviewsHelper: ReviewsHelper, private val reviewsHelper: ReviewsHelper,
private val webDataSafetyHelper: WebDataSafetyHelper, private val webDataSafetyHelper: WebDataSafetyHelper,
@@ -77,7 +83,9 @@ class AppDetailsViewModel @Inject constructor(
checkFavourite(packageName) checkFavourite(packageName)
val app: App = appStash.getOrPut(packageName) { val app: App = appStash.getOrPut(packageName) {
appDetailsHelper.getAppByPackageName(packageName) appDetailsHelper.getAppByPackageName(packageName).apply {
isInstalled = PackageUtil.isInstalled(context, packageName)
}
} }
_app.emit(app) _app.emit(app)
@@ -148,20 +156,42 @@ class AppDetailsViewModel @Inject constructor(
} }
} }
fun fetchUserAppReview(app: App) {
viewModelScope.launch(Dispatchers.IO) {
try {
val stashedUserReview = userReviewStash[app.packageName]
if (stashedUserReview != null) {
_userReview.emit(stashedUserReview)
return@launch
}
val isTesting = app.testingProgram?.isSubscribed ?: false
val userReview = reviewsHelper.getUserReview(app.packageName, isTesting)
if (userReview != null) {
userReviewStash[app.packageName] = userReview
_userReview.emit(userReview)
}
} catch (exception: Exception) {
Log.e(TAG, "Failed to fetch user review", exception)
}
}
}
fun postAppReview(packageName: String, review: Review, isBeta: Boolean) { fun postAppReview(packageName: String, review: Review, isBeta: Boolean) {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
val userReview = userReviewStash.getOrPut(packageName) { val userReview = reviewsHelper.addOrEditReview(
reviewsHelper.addOrEditReview( packageName,
packageName, review.title,
review.title, review.comment,
review.comment, review.rating,
review.rating, isBeta
isBeta )
)
}
if (userReview != null) { if (userReview != null) {
context.toast(R.string.toast_rated_success)
userReviewStash[packageName] = userReview
_userReview.emit(userReview) _userReview.emit(userReview)
} }
} catch (exception: Exception) { } catch (exception: Exception) {

View File

@@ -29,13 +29,13 @@
<RelativeLayout <RelativeLayout
android:id="@+id/img_icon_layout" android:id="@+id/img_icon_layout"
android:layout_width="@dimen/icon_size_medium" android:layout_width="@dimen/icon_size_large"
android:layout_height="@dimen/icon_size_medium"> android:layout_height="@dimen/icon_size_large">
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/img_icon" android:id="@+id/img_icon"
android:layout_width="@dimen/icon_size" android:layout_width="@dimen/icon_size_large"
android:layout_height="@dimen/icon_size" android:layout_height="@dimen/icon_size_large"
tools:src="@drawable/bg_placeholder" /> tools:src="@drawable/bg_placeholder" />
<com.google.android.material.progressindicator.CircularProgressIndicator <com.google.android.material.progressindicator.CircularProgressIndicator
@@ -44,7 +44,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:visibility="gone" android:visibility="gone"
app:indicatorSize="@dimen/icon_size_medium" app:indicatorSize="@dimen/icon_size_large"
app:trackThickness="3dp" app:trackThickness="3dp"
tools:progress="40" /> tools:progress="40" />
</RelativeLayout> </RelativeLayout>
@@ -120,6 +120,7 @@
android:backgroundTint="?colorError" android:backgroundTint="?colorError"
android:textColor="?colorOnError" android:textColor="?colorOnError"
android:visibility="gone" android:visibility="gone"
app:cornerRadius="@dimen/radius_small"
tools:text="@string/action_cancel" tools:text="@string/action_cancel"
tools:visibility="visible" /> tools:visibility="visible" />
@@ -129,6 +130,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_small" android:layout_marginTop="@dimen/margin_small"
android:layout_weight="1" android:layout_weight="1"
app:cornerRadius="@dimen/radius_small"
tools:text="@string/action_install" /> tools:text="@string/action_install" />
</LinearLayout> </LinearLayout>

View File

@@ -22,9 +22,11 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:divider="@drawable/divider"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="@dimen/padding_small" android:paddingStart="@dimen/padding_small"
android:paddingEnd="@dimen/padding_small" android:paddingEnd="@dimen/padding_small"
android:showDividers="middle"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"> tools:visibility="visible">
@@ -40,7 +42,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/margin_small"
android:orientation="vertical"> android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
@@ -61,11 +62,9 @@
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btn_beta_Action" android:id="@+id/btn_beta_Action"
android:layout_width="wrap_content" style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:insetTop="@dimen/margin_xsmall"
android:insetBottom="@dimen/margin_xsmall"
android:minWidth="128dp"
android:text="@string/action_join" android:text="@string/action_join"
app:cornerRadius="@dimen/radius_small" /> app:cornerRadius="@dimen/radius_small" />
</LinearLayout> </LinearLayout>

View File

@@ -19,7 +19,7 @@
~ ~
--> -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/exodus_card" android:id="@+id/exodus_card"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -41,20 +41,14 @@
android:id="@+id/txt_status" android:id="@+id/txt_status"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/header_privacy"
android:text="@string/exodus_progress" android:text="@string/exodus_progress"
android:textAppearance="@style/TextAppearance.Aurora.Line1" /> android:textAppearance="@style/TextAppearance.Aurora.Line1" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
style="@style/Widget.Material3.Button.TonalButton"
android:id="@+id/btn_request_analysis" android:id="@+id/btn_request_analysis"
style="@style/Widget.Material3.Button" android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/txt_status"
android:layout_gravity="center_vertical"
android:insetTop="@dimen/padding_small"
android:insetBottom="@dimen/padding_xsmall"
android:text="@string/action_request_analysis" android:text="@string/action_request_analysis"
app:cornerRadius="@dimen/margin_small" /> app:cornerRadius="@dimen/margin_small" />
</LinearLayout>
</RelativeLayout>

View File

@@ -38,8 +38,9 @@
android:id="@+id/layout_user_review" android:id="@+id/layout_user_review"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:orientation="vertical"
android:orientation="vertical"> android:visibility="gone"
tools:visibility="visible">
<RatingBar <RatingBar
android:id="@+id/user_stars" android:id="@+id/user_stars"
@@ -55,38 +56,39 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginBottom="@dimen/margin_normal"
android:divider="@drawable/divider" android:divider="@drawable/divider"
android:orientation="vertical" android:orientation="vertical"
android:showDividers="middle"> android:showDividers="middle">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputLayout
android:id="@+id/input_title" style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="42dp" android:layout_height="wrap_content">
android:background="@drawable/bg_changelog"
android:gravity="center_vertical|center_horizontal"
android:hint="@string/details_ratings_title_hint"
android:imeOptions="flagNoExtractUi|actionDone"
android:inputType="text"
android:paddingStart="@dimen/padding_large"
android:paddingEnd="@dimen/padding_normal"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.Aurora.Line2" />
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/input_review" android:id="@+id/input_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:hint="@string/details_ratings_title_hint"
android:inputType="text"
android:textAppearance="@style/TextAppearance.Aurora.Line2" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="42dp" android:layout_height="wrap_content">
android:background="@drawable/bg_changelog"
android:gravity="center_vertical|center_horizontal" <com.google.android.material.textfield.TextInputEditText
android:hint="@string/details_think_this_app" android:id="@+id/input_review"
android:imeOptions="flagNoExtractUi|actionDone" android:layout_width="match_parent"
android:inputType="text" android:layout_height="wrap_content"
android:paddingStart="@dimen/padding_large" android:focusable="true"
android:paddingEnd="@dimen/padding_normal" android:hint="@string/details_think_this_app"
android:singleLine="true" android:inputType="textMultiLine"
android:textAppearance="@style/TextAppearance.Aurora.Line2" /> android:textAppearance="@style/TextAppearance.Aurora.Line2" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btn_post_review" android:id="@+id/btn_post_review"
@@ -94,7 +96,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:text="@string/action_post" android:text="@string/action_post"
app:cornerRadius="@dimen/margin_small" /> app:cornerRadius="@dimen/radius_small" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -7,7 +7,7 @@ composeBom = "2024.11.00"
coreVersion = "1.15.0" coreVersion = "1.15.0"
epoxyVersion = "5.1.4" epoxyVersion = "5.1.4"
espressoVersion = "3.6.1" espressoVersion = "3.6.1"
gplayapiVersion = "3.4.3" gplayapiVersion = "3.4.4"
gsonVersion = "2.11.0" gsonVersion = "2.11.0"
hiddenapibypassVersion = "4.3" hiddenapibypassVersion = "4.3"
hiltVersion = "2.53" hiltVersion = "2.53"