From d7f8c9dcb61bfeab3ce69f1d8c221f79100c2a2c Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Thu, 4 Apr 2024 14:11:09 +0600 Subject: [PATCH 01/10] feat: add sharing of app from app details screen --- .../apps/data/application/data/Application.kt | 31 +++++++- .../ui/application/ApplicationFragment.kt | 74 +++++++++++++++++-- .../ui/application/ApplicationViewModel.kt | 35 +++++++-- app/src/main/res/drawable/ic_share.xml | 28 +++++++ .../main/res/layout/fragment_application.xml | 43 +++++++---- app/src/main/res/values-de/strings.xml | 19 +++++ app/src/main/res/values-es/strings.xml | 19 +++++ app/src/main/res/values-fi/strings.xml | 19 +++++ app/src/main/res/values-fr/strings.xml | 19 +++++ app/src/main/res/values-is/strings.xml | 19 +++++ app/src/main/res/values-it/strings.xml | 19 +++++ app/src/main/res/values-nb-rNO/strings.xml | 19 +++++ app/src/main/res/values-nl/strings.xml | 19 +++++ app/src/main/res/values-ru/strings.xml | 19 +++++ app/src/main/res/values-sk/strings.xml | 19 +++++ app/src/main/res/values-sv/strings.xml | 19 +++++ app/src/main/res/values-uk/strings.xml | 19 +++++ app/src/main/res/values/strings.xml | 7 +- 18 files changed, 414 insertions(+), 32 deletions(-) create mode 100644 app/src/main/res/drawable/ic_share.xml diff --git a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt index ba7836bcc..7accac7d0 100644 --- a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt +++ b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt @@ -1,6 +1,5 @@ /* - * Apps Quickly and easily install Android apps onto your device! - * Copyright (C) 2021 E FOUNDATION + * Copyright (C) 2021-2024 MURENA SAS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,11 +13,13 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * */ package foundation.e.apps.data.application.data import android.content.Context +import android.net.Uri import com.aurora.gplayapi.Constants.Restriction import foundation.e.apps.R import foundation.e.apps.data.enums.FilterLevel @@ -94,7 +95,8 @@ data class Application( * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5720 */ var filterLevel: FilterLevel = FilterLevel.UNKNOWN, - var isGplayReplaced: Boolean = false + var isGplayReplaced: Boolean = false, + val on_fdroid: Boolean = false ) { fun updateType() { this.type = if (this.is_pwa) Type.PWA else Type.NATIVE @@ -108,3 +110,26 @@ data class Application( } } } + +val Application.shareUri: Uri + get() { + fun buildFDroidUri(packageName: String): Uri { + val builder = Uri.Builder() + builder.scheme("https") + .authority("f-droid.org") + .appendPath("packages") + .appendPath(packageName) + return builder.build() + } + + fun isFDroidApp(app: Application) = app.on_fdroid + + return when (this.type) { + Type.NATIVE -> when { + isFDroidApp(this) -> buildFDroidUri(this.package_name) + else -> Uri.parse(this.shareUrl) + } + + Type.PWA -> Uri.parse(this.url) + } + } \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt index 021d357d0..fd2c56176 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt @@ -1,6 +1,5 @@ /* - * Apps Quickly and easily install Android apps onto your device! - * Copyright (C) 2021 E FOUNDATION + * Copyright (C) 2021-2024 MURENA SAS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,6 +13,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * */ package foundation.e.apps.ui.application @@ -35,7 +35,9 @@ import androidx.core.graphics.BlendModeCompat import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs @@ -47,32 +49,37 @@ import com.google.android.material.textview.MaterialTextView import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.MainActivity import foundation.e.apps.R +import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.application.data.shareUri import foundation.e.apps.data.cleanapk.CleanApkRetrofit import foundation.e.apps.data.enums.Origin import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.Status import foundation.e.apps.data.enums.User import foundation.e.apps.data.enums.isInitialized -import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.login.exceptions.GPlayLoginException import foundation.e.apps.databinding.FragmentApplicationBinding import foundation.e.apps.di.CommonUtilsModule.LIST_OF_NULL import foundation.e.apps.install.download.data.DownloadProgress -import foundation.e.apps.install.pkg.PWAManager import foundation.e.apps.install.pkg.AppLoungePackageManager +import foundation.e.apps.install.pkg.PWAManager import foundation.e.apps.ui.AppInfoFetchViewModel import foundation.e.apps.ui.MainActivityViewModel import foundation.e.apps.ui.PrivacyInfoViewModel +import foundation.e.apps.ui.application.ShareButtonVisibilityState.Hidden +import foundation.e.apps.ui.application.ShareButtonVisibilityState.Visible import foundation.e.apps.ui.application.model.ApplicationScreenshotsRVAdapter import foundation.e.apps.ui.application.subFrags.ApplicationDialogFragment import foundation.e.apps.ui.parentFragment.TimeoutFragment import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import timber.log.Timber import java.util.Locale import javax.inject.Inject + @AndroidEntryPoint class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { @@ -164,6 +171,8 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { applicationViewModel.errorMessageLiveData.observe(viewLifecycleOwner) { (requireActivity() as MainActivity).showSnackbarMessage(getString(it)) } + + setupShareAction() } private fun updateUi( @@ -447,6 +456,58 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { } } + private fun setupShareAction() { + collectShareVisibilityState() + + fun buildShareIntent(): Intent { + val application = applicationViewModel.application.value?.first + val appName = application?.name + val shareUri = application?.shareUri + val extraText = String.format("%s \n%s", appName, shareUri) + + val uriIntent = Intent(Intent.ACTION_SEND).apply { + setData(shareUri) + putExtra(Intent.EXTRA_TITLE, appName) + } + val textIntent = Intent(Intent.ACTION_SEND).apply { + setType("text/plain") + putExtra(Intent.EXTRA_SUBJECT, appName) + putExtra(Intent.EXTRA_TITLE, appName) + putExtra(Intent.EXTRA_TEXT, extraText) + } + val chooserIntent = Intent.createChooser(textIntent, null) + chooserIntent.putExtra( + Intent.EXTRA_INITIAL_INTENTS, arrayOf( + uriIntent + ) + ) + + return chooserIntent + } + + fun openShareSheet() { + val shareIntent = buildShareIntent() + startActivity(Intent.createChooser(shareIntent, null)) + } + + binding.actionShare.setOnClickListener { + openShareSheet() + } + } + + private fun collectShareVisibilityState() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + applicationViewModel.shareButtonVisibilityState.collectLatest { state -> + when (state) { + Hidden -> binding.actionShare.visibility = View.GONE + Visible -> binding.actionShare.visibility = View.VISIBLE + } + } + } + } + } + override fun loadData(authObjectList: List) { if (isDetailsLoaded) return /* Show the loading bar. */ @@ -780,7 +841,8 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { if (application.is_pwa) { pwaManager.launchPwa(application) } else { - val launchIntent = appLoungePackageManager.getLaunchIntent(application.package_name) + val launchIntent = + appLoungePackageManager.getLaunchIntent(application.package_name) launchIntent?.run { startActivity(this) } } } @@ -795,7 +857,7 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { return } val downloadedSize = "${ - Formatter.formatFileSize(requireContext(), progressResult.second).substringBefore(" MB") + Formatter.formatFileSize(requireContext(), progressResult.second).substringBefore(" MB") }/${Formatter.formatFileSize(requireContext(), progressResult.first)}" val progressPercentage = ((progressResult.second / progressResult.first.toDouble()) * 100f).toInt() diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt index c893fb260..1053f88e9 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt @@ -1,6 +1,5 @@ /* - * Apps Quickly and easily install Android apps onto your device! - * Copyright (C) 2021 E FOUNDATION + * Copyright (C) 2021-2024 MURENA SAS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,6 +13,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * */ package foundation.e.apps.ui.application @@ -24,11 +24,12 @@ import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.exceptions.ApiException import dagger.hilt.android.lifecycle.HiltViewModel import foundation.e.apps.R +import foundation.e.apps.data.application.ApplicationRepository +import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.application.data.shareUri import foundation.e.apps.data.enums.Origin import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.application.ApplicationRepository -import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.fusedDownload.FusedManagerRepository import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.login.AuthObject @@ -36,8 +37,12 @@ import foundation.e.apps.data.login.exceptions.CleanApkException import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.install.download.data.DownloadProgress import foundation.e.apps.install.download.data.DownloadProgressLD +import foundation.e.apps.ui.application.ShareButtonVisibilityState.Hidden +import foundation.e.apps.ui.application.ShareButtonVisibilityState.Visible import foundation.e.apps.ui.parentFragment.LoadingViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -54,6 +59,9 @@ class ApplicationViewModel @Inject constructor( private val _errorMessageLiveData: MutableLiveData = MutableLiveData() val errorMessageLiveData: MutableLiveData = _errorMessageLiveData + private val _shareButtonVisibilityState = MutableStateFlow(Hidden) + val shareButtonVisibilityState = _shareButtonVisibilityState.asStateFlow() + fun loadData( id: String, packageName: String, @@ -105,6 +113,9 @@ class ApplicationViewModel @Inject constructor( ) application.postValue(appData) + val app = appData.first + _shareButtonVisibilityState.value = if (isValidUri(app)) Visible else Hidden + val status = appData.second if (appData.second != ResultStatus.OK) { @@ -142,6 +153,9 @@ class ApplicationViewModel @Inject constructor( _errorMessageLiveData.postValue(R.string.app_not_found) } else { application.postValue(this) + + _shareButtonVisibilityState.value = + if (isValidUri(this.first)) Visible else Hidden } } } catch (e: Exception) { @@ -150,6 +164,8 @@ class ApplicationViewModel @Inject constructor( } } + private fun isValidUri(app: Application) = app.shareUri.toString().isNotBlank() + fun transformPermsToString(): String { var permissionString = "" application.value?.first?.let { @@ -170,12 +186,16 @@ class ApplicationViewModel @Inject constructor( fun getFusedApp(): Application? { return application.value?.first } + fun handleRatingFormat(rating: Double): String { return fusedManagerRepository.handleRatingFormat(rating) } suspend fun calculateProgress(progress: DownloadProgress): Pair { - return fusedManagerRepository.getCalculateProgressWithTotalSize(application.value?.first, progress) + return fusedManagerRepository.getCalculateProgressWithTotalSize( + application.value?.first, + progress + ) } fun updateApplicationStatus(downloadList: List) { @@ -187,3 +207,8 @@ class ApplicationViewModel @Inject constructor( fun isOpenSourceSelected() = applicationRepository.isOpenSourceSelected() } + +sealed class ShareButtonVisibilityState { + object Visible : ShareButtonVisibilityState() + object Hidden : ShareButtonVisibilityState() +} diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 000000000..bedafd4fb --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,28 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_application.xml b/app/src/main/res/layout/fragment_application.xml index e9ef6434a..031fec233 100644 --- a/app/src/main/res/layout/fragment_application.xml +++ b/app/src/main/res/layout/fragment_application.xml @@ -1,6 +1,5 @@ + android:layout_gravity="center" + android:visibility="gone" /> + app:navigationIcon="@drawable/ic_arrow_back"> + + + + + app:drawableLeftCompat="@drawable/ic_warning_white" /> @@ -89,11 +102,11 @@ android:id="@+id/duplicate_app_cardview" android:layout_width="match_parent" android:layout_height="40dp" - android:visibility="gone" android:layout_marginLeft="20dp" - android:layout_marginRight="20dp" android:layout_marginTop="20dp" + android:layout_marginRight="20dp" android:background="@color/e_background" + android:visibility="gone" app:cardElevation="8dp"> + app:drawableEndCompat="@drawable/ic_warning_black" /> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 47e45387d..cf7e68163 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,4 +1,22 @@ + + Kategorien Suche @@ -178,4 +196,5 @@ Einloggen Ignorieren Konto nicht verfügbar + Teilen \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index a3f4a8773..e5604b52f 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,4 +1,22 @@ + + Calificaciones Calificación @@ -178,4 +196,5 @@ \n - limitar el impacto en caso de que esta cuenta sea restringida por Google" Archivo adicional para %s Cuenta no disponible + Compartir \ No newline at end of file diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 7332e7173..0d10a9c76 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -1,4 +1,22 @@ + + %1$d sovelluspäivitys saatavilla @@ -154,4 +172,5 @@ Sinun on kirjauduttava sisään nähdäksesi yleiset sovellukset. PWA ja avoimen lähdekoodin sovellukset Tili ei ole käytettävissä + Jakaa \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 26a7d1081..1e39e48fa 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,4 +1,22 @@ + + Annuler Ouvrir @@ -174,4 +192,5 @@ Connexion Ignorer Compte indisponible + Partager \ No newline at end of file diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 548808e9c..02a5a7352 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -1,4 +1,22 @@ + + Einkunn Setja uppfærslur upp sjálfkrafa @@ -177,4 +195,5 @@ %s vill fá að setja upp viðbótareiningar.Þú þarft að skrá þig aftur inn í AppLounge til að geta sett þær inn. Skrá inn Reikningur ekki í boði + Deila \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 46c6e9b55..3b7ea73e2 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,4 +1,22 @@ + + Apri Ritenta @@ -178,4 +196,5 @@ L\'account anonimo che stai utilizzando non è disponibile. Agiorna la sessione per ottenerne un altro. AGGIORNA SESSIONE Account non disponibile + Condividere \ No newline at end of file diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 4fc1145fa..bc69f613f 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -1,4 +1,22 @@ + + Månedlig Ukentlig @@ -177,4 +195,5 @@ %s vil installere ekstra moduler. Du må logge inn på App Lounge på nytt for å kunne installere dem. Logg inn Konto utilgjengelig + Dele \ No newline at end of file diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 957585699..5fb2b0d44 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -1,4 +1,22 @@ + + Maandelijks Wekelijks @@ -157,4 +175,5 @@ Aanvullend bestand voor %s Update apps geïnstalleerd door andere app-stores Account niet beschikbaar + Delen \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 89fe24e1d..c54e81f27 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1,4 +1,22 @@ + + ОК Закрыть @@ -156,4 +174,5 @@ Пожалуйста, выберите хотя бы один источник приложений. Выйти из системы Аккаунт недоступен + Делиться \ No newline at end of file diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 67e4b3516..30d3efb5b 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -1,4 +1,22 @@ + + Zobraziť dostupné aktualizácie Stiahnutie a inštalácia aktualizácií aplikácií na pozadí @@ -26,4 +44,5 @@ Kategórie Domov Účet nedostupný + Zdieľať \ No newline at end of file diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index f2d8d2440..7c0fdbe7f 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -1,4 +1,22 @@ + + Kategorier Sök @@ -177,4 +195,5 @@ %s vill installera extra moduler. Du måste logga in till AppLounge igen för att kunna installera dom. Logga in Konto otillgängligt + Dela \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index a276b3660..ba144651a 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -1,4 +1,22 @@ + + Недостатньо доступного місця для завантаження цього застосунку! Непередбачувана помилка! @@ -157,4 +175,5 @@ \nНатисніть «Повторити спробу» щоб спробувати знову. Зареєструватися Обліковий запис недоступний + Поділитися \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2cd4f7fb5..344bb732c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,8 +1,6 @@ App Lounge applounge_notification @@ -124,6 +123,8 @@ Additional file for %s Having troubles? https://doc.e.foundation/support-topics/app_lounge_troubleshooting + Share + Update All Checking Updates... -- GitLab From da012eef83e4825442e639703b5e790bf86ade42 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Thu, 4 Apr 2024 15:02:05 +0600 Subject: [PATCH 02/10] refactor: resolve detekt issues --- .../java/foundation/e/apps/data/application/data/Application.kt | 2 +- .../foundation/e/apps/ui/application/ApplicationFragment.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt index 7accac7d0..80347beff 100644 --- a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt +++ b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt @@ -132,4 +132,4 @@ val Application.shareUri: Uri Type.PWA -> Uri.parse(this.url) } - } \ No newline at end of file + } diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt index fd2c56176..b563414c4 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt @@ -463,7 +463,7 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { val application = applicationViewModel.application.value?.first val appName = application?.name val shareUri = application?.shareUri - val extraText = String.format("%s \n%s", appName, shareUri) + val extraText = "$appName \n$shareUri" val uriIntent = Intent(Intent.ACTION_SEND).apply { setData(shareUri) -- GitLab From 8802be462c2576e5e111618a5ca21636eabbd0f1 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Thu, 4 Apr 2024 21:30:34 +0600 Subject: [PATCH 03/10] refactor: move share intent creation to separate class --- .../e/apps/ui/application/AppShareIntent.kt | 47 +++++++++++++++++++ .../ui/application/ApplicationFragment.kt | 47 ++++--------------- 2 files changed, 55 insertions(+), 39 deletions(-) create mode 100644 app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt diff --git a/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt b/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt new file mode 100644 index 000000000..e42b6258c --- /dev/null +++ b/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 MURENA SAS + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + * + */ + +package foundation.e.apps.ui.application + +import android.content.Intent +import android.net.Uri + +object AppShareIntent { + fun create(appName: String, appShareUri: Uri): Intent { + val extraText = "$appName \n$appShareUri" + + val uriIntent = Intent(Intent.ACTION_SEND).apply { + setData(appShareUri) + putExtra(Intent.EXTRA_TITLE, appName) + } + val textIntent = Intent(Intent.ACTION_SEND).apply { + setType("text/plain") + putExtra(Intent.EXTRA_SUBJECT, appName) + putExtra(Intent.EXTRA_TITLE, appName) + putExtra(Intent.EXTRA_TEXT, extraText) + } + val chooserIntent = Intent.createChooser(textIntent, null) + chooserIntent.putExtra( + Intent.EXTRA_INITIAL_INTENTS, arrayOf( + uriIntent + ) + ) + + return chooserIntent + } +} diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt index b563414c4..a38538b11 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt @@ -171,8 +171,6 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { applicationViewModel.errorMessageLiveData.observe(viewLifecycleOwner) { (requireActivity() as MainActivity).showSnackbarMessage(getString(it)) } - - setupShareAction() } private fun updateUi( @@ -227,6 +225,8 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { observeDownloadList() observeDownloadStatus(binding.root) stopLoadingUI() + + collectShareVisibilityState() } private fun showWarningMessage(it: Application) { @@ -454,45 +454,14 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { view.findNavController().navigateUp() } } - } - private fun setupShareAction() { - collectShareVisibilityState() - - fun buildShareIntent(): Intent { - val application = applicationViewModel.application.value?.first - val appName = application?.name - val shareUri = application?.shareUri - val extraText = "$appName \n$shareUri" - - val uriIntent = Intent(Intent.ACTION_SEND).apply { - setData(shareUri) - putExtra(Intent.EXTRA_TITLE, appName) - } - val textIntent = Intent(Intent.ACTION_SEND).apply { - setType("text/plain") - putExtra(Intent.EXTRA_SUBJECT, appName) - putExtra(Intent.EXTRA_TITLE, appName) - putExtra(Intent.EXTRA_TEXT, extraText) - } - val chooserIntent = Intent.createChooser(textIntent, null) - chooserIntent.putExtra( - Intent.EXTRA_INITIAL_INTENTS, arrayOf( - uriIntent - ) - ) - - return chooserIntent - } - - fun openShareSheet() { - val shareIntent = buildShareIntent() - startActivity(Intent.createChooser(shareIntent, null)) - } + binding.actionShare.setOnClickListener { openShareSheet() } + } - binding.actionShare.setOnClickListener { - openShareSheet() - } + private fun openShareSheet() { + val application = applicationViewModel.application.value?.first ?: return + val shareIntent = AppShareIntent.create(application.name, application.shareUri) + startActivity(Intent.createChooser(shareIntent, null)) } private fun collectShareVisibilityState() { -- GitLab From be9ee4ab4104707f00c6590deb9ae18a53c96cb4 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Thu, 4 Apr 2024 22:15:03 +0600 Subject: [PATCH 04/10] refactor: update share visibility and adjust share button layout Refactored the way share button visibility is updated for better code organization. Adjusted share button layout in the application fragment for better UI consistency. Simplified the creation of chooserIntent in AppShareIntent. --- .../e/apps/ui/application/AppShareIntent.kt | 11 +++++------ .../e/apps/ui/application/ApplicationViewModel.kt | 11 ++++++----- app/src/main/res/layout/fragment_application.xml | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt b/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt index e42b6258c..d1156b1e2 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt @@ -29,18 +29,17 @@ object AppShareIntent { setData(appShareUri) putExtra(Intent.EXTRA_TITLE, appName) } + val textIntent = Intent(Intent.ACTION_SEND).apply { setType("text/plain") putExtra(Intent.EXTRA_SUBJECT, appName) putExtra(Intent.EXTRA_TITLE, appName) putExtra(Intent.EXTRA_TEXT, extraText) } - val chooserIntent = Intent.createChooser(textIntent, null) - chooserIntent.putExtra( - Intent.EXTRA_INITIAL_INTENTS, arrayOf( - uriIntent - ) - ) + + val chooserIntent = Intent.createChooser(textIntent, null).apply { + putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(uriIntent)) + } return chooserIntent } diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt index 1053f88e9..4d2de5f0f 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt @@ -113,8 +113,7 @@ class ApplicationViewModel @Inject constructor( ) application.postValue(appData) - val app = appData.first - _shareButtonVisibilityState.value = if (isValidUri(app)) Visible else Hidden + updateShareVisibilityState(appData.first) val status = appData.second @@ -141,6 +140,10 @@ class ApplicationViewModel @Inject constructor( } } + private fun updateShareVisibilityState(app: Application) { + _shareButtonVisibilityState.value = if (isValidUri(app)) Visible else Hidden + } + /* * Dedicated method to get app details from cleanapk using package name. * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5509 @@ -153,9 +156,7 @@ class ApplicationViewModel @Inject constructor( _errorMessageLiveData.postValue(R.string.app_not_found) } else { application.postValue(this) - - _shareButtonVisibilityState.value = - if (isValidUri(this.first)) Visible else Hidden + updateShareVisibilityState(this.first) } } } catch (e: Exception) { diff --git a/app/src/main/res/layout/fragment_application.xml b/app/src/main/res/layout/fragment_application.xml index 031fec233..11660854e 100644 --- a/app/src/main/res/layout/fragment_application.xml +++ b/app/src/main/res/layout/fragment_application.xml @@ -41,12 +41,12 @@ -- GitLab From 51aa2efb1fc2d206ef602058a32d02c2e7e4bcdb Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Thu, 4 Apr 2024 22:21:44 +0600 Subject: [PATCH 05/10] refactor: set initial visibility of share button to hidden --- app/src/main/res/layout/fragment_application.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/fragment_application.xml b/app/src/main/res/layout/fragment_application.xml index 11660854e..cf5974e64 100644 --- a/app/src/main/res/layout/fragment_application.xml +++ b/app/src/main/res/layout/fragment_application.xml @@ -48,7 +48,9 @@ android:contentDescription="@string/share" android:paddingVertical="16dp" android:src="@drawable/ic_share" - app:tint="@color/colorAccent" /> + android:visibility="gone" + app:tint="@color/colorAccent" + tools:visibility="visible" /> -- GitLab From b658b4ca2e302b086ea215bd9a7d4c66fd32895f Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Thu, 4 Apr 2024 22:37:45 +0600 Subject: [PATCH 06/10] refactor: add @SerializedName for better variable naming --- .../foundation/e/apps/data/application/data/Application.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt index 80347beff..32311dbbf 100644 --- a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt +++ b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt @@ -21,6 +21,7 @@ package foundation.e.apps.data.application.data import android.content.Context import android.net.Uri import com.aurora.gplayapi.Constants.Restriction +import com.google.gson.annotations.SerializedName import foundation.e.apps.R import foundation.e.apps.data.enums.FilterLevel import foundation.e.apps.data.enums.Origin @@ -96,7 +97,8 @@ data class Application( */ var filterLevel: FilterLevel = FilterLevel.UNKNOWN, var isGplayReplaced: Boolean = false, - val on_fdroid: Boolean = false + @SerializedName(value = "on_fdroid") + val onFDroid: Boolean = false ) { fun updateType() { this.type = if (this.is_pwa) Type.PWA else Type.NATIVE @@ -122,7 +124,7 @@ val Application.shareUri: Uri return builder.build() } - fun isFDroidApp(app: Application) = app.on_fdroid + fun isFDroidApp(app: Application) = app.onFDroid return when (this.type) { Type.NATIVE -> when { -- GitLab From 6ca20be52e3efafc0ef1d30d888458699121a565 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Thu, 4 Apr 2024 23:56:56 +0600 Subject: [PATCH 07/10] refactor: refine share visibility state update logic Refactored the method `updateShareVisibilityState` to directly accept the shareUri string, rather than the whole Application object. This improves readability and maintainability. Removed the `isValidUri` method, as its logic has been incorporated into `updateShareVisibilityState`. --- .../e/apps/ui/application/ApplicationViewModel.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt index 4d2de5f0f..2148be2f5 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt @@ -113,7 +113,7 @@ class ApplicationViewModel @Inject constructor( ) application.postValue(appData) - updateShareVisibilityState(appData.first) + updateShareVisibilityState(appData.first.shareUri.toString()) val status = appData.second @@ -140,8 +140,9 @@ class ApplicationViewModel @Inject constructor( } } - private fun updateShareVisibilityState(app: Application) { - _shareButtonVisibilityState.value = if (isValidUri(app)) Visible else Hidden + private fun updateShareVisibilityState(shareUri: String) { + val isValidUri = shareUri.isNotBlank() + _shareButtonVisibilityState.value = if (isValidUri) Visible else Hidden } /* @@ -156,7 +157,7 @@ class ApplicationViewModel @Inject constructor( _errorMessageLiveData.postValue(R.string.app_not_found) } else { application.postValue(this) - updateShareVisibilityState(this.first) + updateShareVisibilityState(first.shareUri.toString()) } } } catch (e: Exception) { @@ -165,8 +166,6 @@ class ApplicationViewModel @Inject constructor( } } - private fun isValidUri(app: Application) = app.shareUri.toString().isNotBlank() - fun transformPermsToString(): String { var permissionString = "" application.value?.first?.let { -- GitLab From ed9a325f9598835d832145324e85a282e6209864 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Fri, 5 Apr 2024 15:42:28 +0600 Subject: [PATCH 08/10] feat: refactor Intent creation in AppShareIntent Changed the Intent creation process in AppShareIntent.kt. --- .../java/foundation/e/apps/ui/application/AppShareIntent.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt b/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt index d1156b1e2..421c4aef4 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt @@ -37,10 +37,10 @@ object AppShareIntent { putExtra(Intent.EXTRA_TEXT, extraText) } - val chooserIntent = Intent.createChooser(textIntent, null).apply { + val shareIntent = Intent(textIntent).apply { putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(uriIntent)) } - return chooserIntent + return shareIntent } } -- GitLab From 1be37454d1090270a60ebbcda2cd883ec3e13625 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Sat, 6 Apr 2024 15:32:41 +0600 Subject: [PATCH 09/10] refactor: remove local functions from getter Refactored the Application data class to simplify code and improve readability. Also improved the 'shareUri' getter to make it more concise. --- .../apps/data/application/data/Application.kt | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt index 32311dbbf..efc296cbb 100644 --- a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt +++ b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt @@ -27,6 +27,8 @@ import foundation.e.apps.data.enums.FilterLevel import foundation.e.apps.data.enums.Origin import foundation.e.apps.data.enums.Status import foundation.e.apps.data.enums.Type +import foundation.e.apps.data.enums.Type.NATIVE +import foundation.e.apps.data.enums.Type.PWA import foundation.e.apps.di.CommonUtilsModule.LIST_OF_NULL data class Application( @@ -59,7 +61,7 @@ data class Application( val is_pwa: Boolean = false, var pwaPlayerDbId: Long = -1, val url: String = String(), - var type: Type = Type.NATIVE, + var type: Type = NATIVE, var privacyScore: Int = -1, var isPurchased: Boolean = false, @@ -98,10 +100,10 @@ data class Application( var filterLevel: FilterLevel = FilterLevel.UNKNOWN, var isGplayReplaced: Boolean = false, @SerializedName(value = "on_fdroid") - val onFDroid: Boolean = false + val isFDroidApp: Boolean = false ) { fun updateType() { - this.type = if (this.is_pwa) Type.PWA else Type.NATIVE + this.type = if (this.is_pwa) PWA else NATIVE } fun updateSource(context: Context) { @@ -114,24 +116,19 @@ data class Application( } val Application.shareUri: Uri - get() { - fun buildFDroidUri(packageName: String): Uri { - val builder = Uri.Builder() - builder.scheme("https") - .authority("f-droid.org") - .appendPath("packages") - .appendPath(packageName) - return builder.build() - } - - fun isFDroidApp(app: Application) = app.onFDroid - - return when (this.type) { - Type.NATIVE -> when { - isFDroidApp(this) -> buildFDroidUri(this.package_name) - else -> Uri.parse(this.shareUrl) - } - - Type.PWA -> Uri.parse(this.url) + get() = when (type) { + PWA -> Uri.parse(url) + NATIVE -> when { + isFDroidApp -> buildFDroidUri(package_name) + else -> Uri.parse(shareUrl) } } + +private fun buildFDroidUri(packageName: String): Uri { + val builder = Uri.Builder() + builder.scheme("https") + .authority("f-droid.org") + .appendPath("packages") + .appendPath(packageName) + return builder.build() +} -- GitLab From f619444ad7f5df1dae91b997c32982a607e1a8be Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Mon, 8 Apr 2024 12:29:28 +0600 Subject: [PATCH 10/10] refactor: optimize buildFDroidUri method in Application.kt --- .../foundation/e/apps/data/application/data/Application.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt index efc296cbb..ffc19d94c 100644 --- a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt +++ b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt @@ -125,10 +125,10 @@ val Application.shareUri: Uri } private fun buildFDroidUri(packageName: String): Uri { - val builder = Uri.Builder() - builder.scheme("https") + return Uri.Builder() + .scheme("https") .authority("f-droid.org") .appendPath("packages") .appendPath(packageName) - return builder.build() + .build() } -- GitLab