@@ -129,6 +129,11 @@ class MainActivity : ComponentActivity() {
129129 private var onMediaProjectionPermissionGranted: (() -> Unit )? = null
130130 private var onWebRtcMediaProjectionResult: ((Int , Intent ) -> Unit )? = null
131131
132+ // Payment Dialog State (Task 6)
133+ private var showPaymentMethodDialog by mutableStateOf(false )
134+ private var showPayPalWebViewDialog by mutableStateOf(false )
135+ private var paypalSubscriptionId by mutableStateOf(" " )
136+
132137 private val screenshotRequestHandler = object : BroadcastReceiver () {
133138 override fun onReceive (context : Context ? , intent : Intent ? ) {
134139 if (intent?.action == ACTION_REQUEST_MEDIAPROJECTION_SCREENSHOT ) {
@@ -326,7 +331,7 @@ class MainActivity : ComponentActivity() {
326331 }
327332 } else if (billingResult.responseCode == BillingClient .BillingResponseCode .USER_CANCELED ) {
328333 Log .i(TAG , " purchasesUpdatedListener: User cancelled the purchase flow." )
329- Toast .makeText(this , " Donation process cancelled." , Toast .LENGTH_SHORT ).show()
334+ Toast .makeText(this , " Support cancelled." , Toast .LENGTH_SHORT ).show()
330335 } else {
331336 Log .e(TAG , " purchasesUpdatedListener: Billing error: ${billingResult.debugMessage} (Code: ${billingResult.responseCode} )" )
332337 Toast .makeText(this , " Error during donation process: ${billingResult.debugMessage} " , Toast .LENGTH_LONG ).show()
@@ -636,6 +641,116 @@ class MainActivity : ComponentActivity() {
636641 }
637642 }
638643 }
644+
645+ // Task 6: Payment Method Dialog
646+ if (showPaymentMethodDialog) {
647+ AlertDialog (
648+ onDismissRequest = { showPaymentMethodDialog = false },
649+ title = { Text (" Choose Payment Method" ) },
650+ text = {
651+ Column {
652+ Button (
653+ onClick = {
654+ showPaymentMethodDialog = false
655+ showPayPalWebViewDialog = true
656+ },
657+ modifier = Modifier .fillMaxWidth().padding(bottom = 8 .dp)
658+ ) {
659+ Text (" PayPal (2,60 €/Month)" )
660+ }
661+ Button (
662+ onClick = {
663+ showPaymentMethodDialog = false
664+ launchGooglePlayBilling()
665+ },
666+ modifier = Modifier .fillMaxWidth()
667+ ) {
668+ Text (" Google Play (2,90 €/Month)" )
669+ }
670+ }
671+ },
672+ confirmButton = {},
673+ dismissButton = {
674+ TextButton (onClick = { showPaymentMethodDialog = false }) {
675+ Text (" Cancel" )
676+ }
677+ }
678+ )
679+ }
680+
681+ // Task 6: PayPal WebView Dialog
682+ if (showPayPalWebViewDialog) {
683+ Dialog (onDismissRequest = { showPayPalWebViewDialog = false }) {
684+ Card (modifier = Modifier .fillMaxSize().padding(16 .dp)) {
685+ Column (modifier = Modifier .fillMaxSize()) {
686+ Row (
687+ modifier = Modifier .fillMaxWidth().padding(8 .dp),
688+ horizontalArrangement = Arrangement .SpaceBetween ,
689+ verticalAlignment = Alignment .CenterVertically
690+ ) {
691+ Text (" PayPal Subscription" , style = MaterialTheme .typography.titleMedium)
692+ TextButton (onClick = { showPayPalWebViewDialog = false }) {
693+ Text (" Close" )
694+ }
695+ }
696+
697+ androidx.compose.ui.viewinterop.AndroidView (
698+ factory = { ctx ->
699+ android.webkit.WebView (ctx).apply {
700+ settings.javaScriptEnabled = true
701+ settings.domStorageEnabled = true
702+ webViewClient = android.webkit.WebViewClient ()
703+
704+ // Generate Short UUID
705+ val shortId = java.util.UUID .randomUUID().toString().substring(0 , 8 )
706+
707+ // Save it to SharedPreferences
708+ ctx.getSharedPreferences(PREFS_NAME , Context .MODE_PRIVATE )
709+ .edit()
710+ .putString(" payment_support_id" , shortId)
711+ .apply ()
712+
713+ val html = """
714+ <!DOCTYPE html>
715+ <html>
716+ <head>
717+ <meta name="viewport" content="width=device-width, initial-scale=1">
718+ </head>
719+ <body>
720+ <div id="paypal-button-container-P-5J921557TD348880GNGUCRSI"></div>
721+ <script src="https://www.paypal.com/sdk/js?client-id=AQ52P9G85S3RCHw7lWnEDH_Pudk-5JdE8S6gBfS72jWwMng-xR-0qNrtmS8Mv5RtdK--a1cZ0G-12_rZ&vault=true&intent=subscription" data-sdk-integration-source="button-factory"></script>
722+ <script>
723+ paypal.Buttons({
724+ style: {
725+ shape: 'rect',
726+ color: 'gold',
727+ layout: 'vertical',
728+ label: 'subscribe'
729+ },
730+ createSubscription: function(data, actions) {
731+ return actions.subscription.create({
732+ 'plan_id': 'P-5J921557TD348880GNGUCRSI',
733+ 'custom_id': '$shortId '
734+ });
735+ },
736+ onApprove: function(data, actions) {
737+ alert('Thank you for your subscription! Your Support ID is: $shortId ');
738+ }
739+ }).render('#paypal-button-container-P-5J921557TD348880GNGUCRSI');
740+ </script>
741+ </body>
742+ </html>
743+ """ .trimIndent()
744+
745+ loadDataWithBaseURL(" https://www.paypal.com" , html, " text/html" , " UTF-8" , null )
746+ }
747+ },
748+ modifier = Modifier .fillMaxSize()
749+ )
750+ }
751+ }
752+ }
753+ }
639754 }
640755 }
641756 }
@@ -880,28 +995,32 @@ class MainActivity : ComponentActivity() {
880995 }
881996
882997 private fun initiateDonationPurchase () {
883- Log .d(TAG , " initiateDonationPurchase called." )
998+ Log .d(TAG , " initiateDonationPurchase called. Showing Payment Method Dialog." )
999+ showPaymentMethodDialog = true
1000+ }
1001+
1002+ private fun launchGooglePlayBilling () {
8841003 if (! ::billingClient.isInitialized) {
885- Log .e(TAG , " initiateDonationPurchase : BillingClient not initialized." )
1004+ Log .e(TAG , " launchGooglePlayBilling : BillingClient not initialized." )
8861005 updateStatusMessage(" Payment service not initialized. Please try again later." , true )
8871006 return
8881007 }
8891008 if (! billingClient.isReady) {
890- Log .e(TAG , " initiateDonationPurchase : BillingClient not ready. Connection state: ${billingClient.connectionState} " )
1009+ Log .e(TAG , " launchGooglePlayBilling : BillingClient not ready. Connection state: ${billingClient.connectionState} " )
8911010 updateStatusMessage(" Payment service not ready. Please try again later." , true )
8921011 if (billingClient.connectionState == BillingClient .ConnectionState .CLOSED || billingClient.connectionState == BillingClient .ConnectionState .DISCONNECTED ){
893- Log .d(TAG , " initiateDonationPurchase : BillingClient disconnected, attempting to reconnect." )
1012+ Log .d(TAG , " launchGooglePlayBilling : BillingClient disconnected, attempting to reconnect." )
8941013 billingClient.startConnection(object : BillingClientStateListener {
8951014 override fun onBillingSetupFinished (setupResult : BillingResult ) {
896- Log .i(TAG , " initiateDonationPurchase (reconnect): onBillingSetupFinished. ResponseCode: ${setupResult.responseCode} " )
1015+ Log .i(TAG , " launchGooglePlayBilling (reconnect): onBillingSetupFinished. ResponseCode: ${setupResult.responseCode} " )
8971016 if (setupResult.responseCode == BillingClient .BillingResponseCode .OK ) {
898- Log .d(TAG , " initiateDonationPurchase (reconnect): Reconnection successful, retrying purchase." )
899- initiateDonationPurchase ()
1017+ Log .d(TAG , " launchGooglePlayBilling (reconnect): Reconnection successful, retrying purchase." )
1018+ launchGooglePlayBilling ()
9001019 } else {
901- Log .e(TAG , " initiateDonationPurchase (reconnect): BillingClient setup failed after disconnect: ${setupResult.debugMessage} " )
1020+ Log .e(TAG , " launchGooglePlayBilling (reconnect): BillingClient setup failed after disconnect: ${setupResult.debugMessage} " )
9021021 }
9031022 }
904- override fun onBillingServiceDisconnected () { Log .w(TAG , " initiateDonationPurchase (reconnect): BillingClient still disconnected." ) }
1023+ override fun onBillingServiceDisconnected () { Log .w(TAG , " launchGooglePlayBilling (reconnect): BillingClient still disconnected." ) }
9051024 })
9061025 }
9071026 return
0 commit comments