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 ba7836bcc60e1eb561b73113c21e03837dee9f25..ffc19d94c345ea9feab2075a17e53e8d0de97707 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,17 +13,22 @@ * * 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 com.google.gson.annotations.SerializedName import foundation.e.apps.R 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( @@ -57,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, @@ -94,10 +98,12 @@ 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, + @SerializedName(value = "on_fdroid") + 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) { @@ -108,3 +114,21 @@ data class Application( } } } + +val Application.shareUri: Uri + get() = when (type) { + PWA -> Uri.parse(url) + NATIVE -> when { + isFDroidApp -> buildFDroidUri(package_name) + else -> Uri.parse(shareUrl) + } + } + +private fun buildFDroidUri(packageName: String): Uri { + return Uri.Builder() + .scheme("https") + .authority("f-droid.org") + .appendPath("packages") + .appendPath(packageName) + .build() +} 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 0000000000000000000000000000000000000000..421c4aef4ffe3836436b904a08e489031f55a49d --- /dev/null +++ b/app/src/main/java/foundation/e/apps/ui/application/AppShareIntent.kt @@ -0,0 +1,46 @@ +/* + * 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 shareIntent = Intent(textIntent).apply { + putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(uriIntent)) + } + + return shareIntent + } +} 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 021d357d05fcb6da9b722443f3a53c3bea6ce994..a38538b11b35c2e3f4c874f4109e2e0756ec542f 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) { @@ -218,6 +225,8 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { observeDownloadList() observeDownloadStatus(binding.root) stopLoadingUI() + + collectShareVisibilityState() } private fun showWarningMessage(it: Application) { @@ -445,6 +454,27 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { view.findNavController().navigateUp() } } + + 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() { + 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) { @@ -780,7 +810,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 +826,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 c893fb260381e866649e88cc25df8c692c7b4671..2148be2f55bdbe16c7201fcf81b84bb3f2442790 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,8 @@ class ApplicationViewModel @Inject constructor( ) application.postValue(appData) + updateShareVisibilityState(appData.first.shareUri.toString()) + val status = appData.second if (appData.second != ResultStatus.OK) { @@ -130,6 +140,11 @@ class ApplicationViewModel @Inject constructor( } } + private fun updateShareVisibilityState(shareUri: String) { + val isValidUri = shareUri.isNotBlank() + _shareButtonVisibilityState.value = if (isValidUri) Visible else Hidden + } + /* * Dedicated method to get app details from cleanapk using package name. * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5509 @@ -142,6 +157,7 @@ class ApplicationViewModel @Inject constructor( _errorMessageLiveData.postValue(R.string.app_not_found) } else { application.postValue(this) + updateShareVisibilityState(first.shareUri.toString()) } } } catch (e: Exception) { @@ -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 0000000000000000000000000000000000000000..bedafd4fb20794cbbefb5fe812328bc34301d96d --- /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 e9ef6434a4350d719fccd2aba64a843fc5b4824e..cf5974e64599ee2e7576c42c3b056050667a1eee 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 +104,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 47e45387da67b031185991d74c65c277520fc0bc..cf7e68163656219f9e22cd04ec6cce37b8e57482 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 a3f4a87734c12bac499eba11989ea33b802122b0..e5604b52fc72c829858ce054bd50a217f740e20c 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 7332e717322bc09e8e90a4b8ff8637433655a1e2..0d10a9c767dfdf288cb1f0622d1c359c02a48b96 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 26a7d10813f171e5c7fa92cccf3168975ee93c2c..1e39e48fa33df1a4c0d78d4090facd78517829e0 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 548808e9cd06f3e5fc87742eb1b86cf34c52b8b6..02a5a73526f42b1a60e62c80fa2b4bf99ee2eeda 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 46c6e9b55a6b555a60b050195f9f4fd1b62b9d0d..3b7ea73e2a61a8667e93b6f451c436418c2373ee 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 4fc1145fabe33f903468c2ff8e1d2c70327e7e30..bc69f613f06bbafa94a29385c7e34197c9e55c64 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 9575856995a9db4852d1a7efb17ee870128977f4..5fb2b0d445843692a0a0b0589c4d0647d16fb55b 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 89fe24e1d496a3bffd39ad51dbc73700a39e6959..c54e81f273e50d5d258821e01b81a8c7cbbf2757 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 67e4b3516770fe0e87a95c08e34178eed36d0dd3..30d3efb5b920162199e557174916e8fe6f91820e 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 f2d8d2440fe41f3d33d58798b171c4bc07aea06b..7c0fdbe7f1d4973d4faac040719db0ea0ad186c7 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 a276b3660e0866bfb1f560a74596be176c040843..ba144651a276efb7224229a8937aa1be871a860e 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 2cd4f7fb59636738af2a05f40dd356f162e0daf5..344bb732c16df61f2ca0bfea3d3c7b5e7e40dcf6 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...