AppDetails: Fix user review + minor cleanup
This commit is contained in:
@@ -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" />
|
||||||
|
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user