Showing
6 changed files
with
87 additions
and
95 deletions
| 1 | +import 'package:doublefeel_flutter/app/modules/login/views/email_login_contact_us_bottom_sheet.dart'; | ||
| 1 | import 'package:doublefeel_flutter/core/logging/app_logger.dart'; | 2 | import 'package:doublefeel_flutter/core/logging/app_logger.dart'; |
| 2 | import 'package:doublefeel_flutter/core/network/api/pay_api.dart'; | 3 | import 'package:doublefeel_flutter/core/network/api/pay_api.dart'; |
| 3 | import 'package:doublefeel_flutter/core/network/api/vip_api.dart'; | 4 | import 'package:doublefeel_flutter/core/network/api/vip_api.dart'; |
| @@ -176,7 +177,7 @@ class MembershipDetailController extends GetxController { | @@ -176,7 +177,7 @@ class MembershipDetailController extends GetxController { | ||
| 176 | } | 177 | } |
| 177 | 178 | ||
| 178 | void openContactUs() { | 179 | void openContactUs() { |
| 179 | - Get.toNamed(Routes.SUBMIT_FEEDBACK); | 180 | + feedbackCompat(pageName: 'Subscription page'); |
| 180 | } | 181 | } |
| 181 | 182 | ||
| 182 | Future<void> manageSubscription() async { | 183 | Future<void> manageSubscription() async { |
| @@ -8,6 +8,7 @@ import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart'; | @@ -8,6 +8,7 @@ import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart'; | ||
| 8 | import 'package:doublefeel_flutter/data/models/local/user_preferences.dart'; | 8 | import 'package:doublefeel_flutter/data/models/local/user_preferences.dart'; |
| 9 | import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; | 9 | import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; |
| 10 | import 'package:doublefeel_flutter/l10n/l10n_extensions.dart' as context; | 10 | import 'package:doublefeel_flutter/l10n/l10n_extensions.dart' as context; |
| 11 | +import 'package:flutter/gestures.dart'; | ||
| 11 | import 'package:flutter/material.dart'; | 12 | import 'package:flutter/material.dart'; |
| 12 | import 'package:get/get.dart'; | 13 | import 'package:get/get.dart'; |
| 13 | import 'package:intl/intl.dart'; | 14 | import 'package:intl/intl.dart'; |
| @@ -410,7 +411,7 @@ class _LegalNotes extends StatelessWidget { | @@ -410,7 +411,7 @@ class _LegalNotes extends StatelessWidget { | ||
| 410 | } | 411 | } |
| 411 | } | 412 | } |
| 412 | 413 | ||
| 413 | -class _LegalText extends StatelessWidget { | 414 | +class _LegalText extends StatefulWidget { |
| 414 | const _LegalText({ | 415 | const _LegalText({ |
| 415 | required this.prefix, | 416 | required this.prefix, |
| 416 | required this.text, | 417 | required this.text, |
| @@ -425,6 +426,31 @@ class _LegalText extends StatelessWidget { | @@ -425,6 +426,31 @@ class _LegalText extends StatelessWidget { | ||
| 425 | final String? linkSuffix; | 426 | final String? linkSuffix; |
| 426 | final VoidCallback? onLinkTap; | 427 | final VoidCallback? onLinkTap; |
| 427 | 428 | ||
| 429 | + @override | ||
| 430 | + State<_LegalText> createState() => _LegalTextState(); | ||
| 431 | +} | ||
| 432 | + | ||
| 433 | +class _LegalTextState extends State<_LegalText> { | ||
| 434 | + late final TapGestureRecognizer _linkRecognizer; | ||
| 435 | + | ||
| 436 | + @override | ||
| 437 | + void initState() { | ||
| 438 | + super.initState(); | ||
| 439 | + _linkRecognizer = TapGestureRecognizer()..onTap = widget.onLinkTap; | ||
| 440 | + } | ||
| 441 | + | ||
| 442 | + @override | ||
| 443 | + void didUpdateWidget(covariant _LegalText oldWidget) { | ||
| 444 | + super.didUpdateWidget(oldWidget); | ||
| 445 | + _linkRecognizer.onTap = widget.onLinkTap; | ||
| 446 | + } | ||
| 447 | + | ||
| 448 | + @override | ||
| 449 | + void dispose() { | ||
| 450 | + _linkRecognizer.dispose(); | ||
| 451 | + super.dispose(); | ||
| 452 | + } | ||
| 453 | + | ||
| 428 | static const _baseStyle = TextStyle( | 454 | static const _baseStyle = TextStyle( |
| 429 | color: PurchaseColors.subtitle, | 455 | color: PurchaseColors.subtitle, |
| 430 | fontSize: 12, | 456 | fontSize: 12, |
| @@ -441,48 +467,25 @@ class _LegalText extends StatelessWidget { | @@ -441,48 +467,25 @@ class _LegalText extends StatelessWidget { | ||
| 441 | TextSpan _buildTextSpan() => TextSpan( | 467 | TextSpan _buildTextSpan() => TextSpan( |
| 442 | style: _baseStyle, | 468 | style: _baseStyle, |
| 443 | children: [ | 469 | children: [ |
| 444 | - TextSpan(text: text), | ||
| 445 | - if (linkText case final linkText?) | ||
| 446 | - TextSpan(text: linkText, style: _linkStyle), | ||
| 447 | - if (linkSuffix case final linkSuffix?) TextSpan(text: linkSuffix), | 470 | + TextSpan(text: widget.text), |
| 471 | + if (widget.linkText case final linkText?) | ||
| 472 | + TextSpan( | ||
| 473 | + text: linkText, | ||
| 474 | + style: _linkStyle, | ||
| 475 | + recognizer: widget.onLinkTap == null ? null : _linkRecognizer, | ||
| 476 | + ), | ||
| 477 | + if (widget.linkSuffix case final linkSuffix?) | ||
| 478 | + TextSpan(text: linkSuffix), | ||
| 448 | ], | 479 | ], |
| 449 | ); | 480 | ); |
| 450 | 481 | ||
| 451 | - void _handleTapUp( | ||
| 452 | - BuildContext context, | ||
| 453 | - BoxConstraints constraints, | ||
| 454 | - TapUpDetails details, | ||
| 455 | - ) { | ||
| 456 | - final linkText = this.linkText; | ||
| 457 | - if (linkText == null || onLinkTap == null) return; | ||
| 458 | - | ||
| 459 | - final painter = TextPainter( | ||
| 460 | - text: _buildTextSpan(), | ||
| 461 | - textDirection: Directionality.of(context), | ||
| 462 | - textScaler: MediaQuery.textScalerOf(context), | ||
| 463 | - )..layout(maxWidth: constraints.maxWidth); | ||
| 464 | - final linkStart = text.length; | ||
| 465 | - final linkBoxes = painter.getBoxesForSelection( | ||
| 466 | - TextSelection( | ||
| 467 | - baseOffset: linkStart, | ||
| 468 | - extentOffset: linkStart + linkText.length, | ||
| 469 | - ), | ||
| 470 | - ); | ||
| 471 | - | ||
| 472 | - if (linkBoxes.any( | ||
| 473 | - (box) => box.toRect().inflate(10).contains(details.localPosition), | ||
| 474 | - )) { | ||
| 475 | - onLinkTap!.call(); | ||
| 476 | - } | ||
| 477 | - } | ||
| 478 | - | ||
| 479 | @override | 482 | @override |
| 480 | Widget build(BuildContext context) { | 483 | Widget build(BuildContext context) { |
| 481 | return Row( | 484 | return Row( |
| 482 | crossAxisAlignment: CrossAxisAlignment.start, | 485 | crossAxisAlignment: CrossAxisAlignment.start, |
| 483 | children: [ | 486 | children: [ |
| 484 | Text( | 487 | Text( |
| 485 | - prefix, | 488 | + widget.prefix, |
| 486 | style: const TextStyle( | 489 | style: const TextStyle( |
| 487 | color: PurchaseColors.subtitle, | 490 | color: PurchaseColors.subtitle, |
| 488 | fontSize: 12, | 491 | fontSize: 12, |
| @@ -490,17 +493,9 @@ class _LegalText extends StatelessWidget { | @@ -490,17 +493,9 @@ class _LegalText extends StatelessWidget { | ||
| 490 | ), | 493 | ), |
| 491 | ), | 494 | ), |
| 492 | Expanded( | 495 | Expanded( |
| 493 | - child: LayoutBuilder( | ||
| 494 | - builder: (context, constraints) => GestureDetector( | ||
| 495 | - behavior: HitTestBehavior.opaque, | ||
| 496 | - onTapUp: linkText == null || onLinkTap == null | ||
| 497 | - ? null | ||
| 498 | - : (details) => _handleTapUp(context, constraints, details), | ||
| 499 | - child: Text.rich( | ||
| 500 | - _buildTextSpan(), | ||
| 501 | - textScaler: MediaQuery.textScalerOf(context), | ||
| 502 | - ), | ||
| 503 | - ), | 496 | + child: Text.rich( |
| 497 | + _buildTextSpan(), | ||
| 498 | + textScaler: MediaQuery.textScalerOf(context), | ||
| 504 | ), | 499 | ), |
| 505 | ), | 500 | ), |
| 506 | ], | 501 | ], |
| 1 | import 'dart:async'; | 1 | import 'dart:async'; |
| 2 | 2 | ||
| 3 | +import 'package:doublefeel_flutter/app/modules/login/views/email_login_contact_us_bottom_sheet.dart'; | ||
| 3 | import 'package:doublefeel_flutter/app/routes/app_pages.dart'; | 4 | import 'package:doublefeel_flutter/app/routes/app_pages.dart'; |
| 4 | import 'package:doublefeel_flutter/core/config/app_environment_config.dart'; | 5 | import 'package:doublefeel_flutter/core/config/app_environment_config.dart'; |
| 5 | import 'package:doublefeel_flutter/core/constants/app_const.dart'; | 6 | import 'package:doublefeel_flutter/core/constants/app_const.dart'; |
| @@ -394,7 +395,7 @@ class PurchaseController extends GetxController { | @@ -394,7 +395,7 @@ class PurchaseController extends GetxController { | ||
| 394 | 395 | ||
| 395 | void openContactUs() { | 396 | void openContactUs() { |
| 396 | _trackClickVipCenter('联系我们'); | 397 | _trackClickVipCenter('联系我们'); |
| 397 | - Get.toNamed(Routes.SUBMIT_FEEDBACK); | 398 | + feedbackCompat(pageName: 'Subscription page'); |
| 398 | } | 399 | } |
| 399 | 400 | ||
| 400 | void openUserTerms() { | 401 | void openUserTerms() { |
| @@ -3,6 +3,7 @@ import 'package:doublefeel_flutter/app/widget/premium_benefit_list_view.dart'; | @@ -3,6 +3,7 @@ import 'package:doublefeel_flutter/app/widget/premium_benefit_list_view.dart'; | ||
| 3 | import 'package:doublefeel_flutter/core/util/size_extensions.dart'; | 3 | import 'package:doublefeel_flutter/core/util/size_extensions.dart'; |
| 4 | import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; | 4 | import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; |
| 5 | import 'package:doublefeel_flutter/r.dart'; | 5 | import 'package:doublefeel_flutter/r.dart'; |
| 6 | +import 'package:flutter/gestures.dart'; | ||
| 6 | import 'package:flutter/material.dart'; | 7 | import 'package:flutter/material.dart'; |
| 7 | import 'package:flutter/services.dart'; | 8 | import 'package:flutter/services.dart'; |
| 8 | import 'package:get/get.dart'; | 9 | import 'package:get/get.dart'; |
| @@ -287,7 +288,7 @@ class _LegalNotes extends StatelessWidget { | @@ -287,7 +288,7 @@ class _LegalNotes extends StatelessWidget { | ||
| 287 | } | 288 | } |
| 288 | } | 289 | } |
| 289 | 290 | ||
| 290 | -class _LegalText extends StatelessWidget { | 291 | +class _LegalText extends StatefulWidget { |
| 291 | const _LegalText({ | 292 | const _LegalText({ |
| 292 | required this.prefix, | 293 | required this.prefix, |
| 293 | required this.text, | 294 | required this.text, |
| @@ -302,6 +303,31 @@ class _LegalText extends StatelessWidget { | @@ -302,6 +303,31 @@ class _LegalText extends StatelessWidget { | ||
| 302 | final String? linkSuffix; | 303 | final String? linkSuffix; |
| 303 | final VoidCallback? onLinkTap; | 304 | final VoidCallback? onLinkTap; |
| 304 | 305 | ||
| 306 | + @override | ||
| 307 | + State<_LegalText> createState() => _LegalTextState(); | ||
| 308 | +} | ||
| 309 | + | ||
| 310 | +class _LegalTextState extends State<_LegalText> { | ||
| 311 | + late final TapGestureRecognizer _linkRecognizer; | ||
| 312 | + | ||
| 313 | + @override | ||
| 314 | + void initState() { | ||
| 315 | + super.initState(); | ||
| 316 | + _linkRecognizer = TapGestureRecognizer()..onTap = widget.onLinkTap; | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + @override | ||
| 320 | + void didUpdateWidget(covariant _LegalText oldWidget) { | ||
| 321 | + super.didUpdateWidget(oldWidget); | ||
| 322 | + _linkRecognizer.onTap = widget.onLinkTap; | ||
| 323 | + } | ||
| 324 | + | ||
| 325 | + @override | ||
| 326 | + void dispose() { | ||
| 327 | + _linkRecognizer.dispose(); | ||
| 328 | + super.dispose(); | ||
| 329 | + } | ||
| 330 | + | ||
| 305 | static const _baseStyle = TextStyle( | 331 | static const _baseStyle = TextStyle( |
| 306 | color: PurchaseColors.subtitle, | 332 | color: PurchaseColors.subtitle, |
| 307 | fontSize: 12, | 333 | fontSize: 12, |
| @@ -318,48 +344,25 @@ class _LegalText extends StatelessWidget { | @@ -318,48 +344,25 @@ class _LegalText extends StatelessWidget { | ||
| 318 | TextSpan _buildTextSpan() => TextSpan( | 344 | TextSpan _buildTextSpan() => TextSpan( |
| 319 | style: _baseStyle, | 345 | style: _baseStyle, |
| 320 | children: [ | 346 | children: [ |
| 321 | - TextSpan(text: text), | ||
| 322 | - if (linkText case final linkText?) | ||
| 323 | - TextSpan(text: linkText, style: _linkStyle), | ||
| 324 | - if (linkSuffix case final linkSuffix?) TextSpan(text: linkSuffix), | 347 | + TextSpan(text: widget.text), |
| 348 | + if (widget.linkText case final linkText?) | ||
| 349 | + TextSpan( | ||
| 350 | + text: linkText, | ||
| 351 | + style: _linkStyle, | ||
| 352 | + recognizer: widget.onLinkTap == null ? null : _linkRecognizer, | ||
| 353 | + ), | ||
| 354 | + if (widget.linkSuffix case final linkSuffix?) | ||
| 355 | + TextSpan(text: linkSuffix), | ||
| 325 | ], | 356 | ], |
| 326 | ); | 357 | ); |
| 327 | 358 | ||
| 328 | - void _handleTapUp( | ||
| 329 | - BuildContext context, | ||
| 330 | - BoxConstraints constraints, | ||
| 331 | - TapUpDetails details, | ||
| 332 | - ) { | ||
| 333 | - final linkText = this.linkText; | ||
| 334 | - if (linkText == null || onLinkTap == null) return; | ||
| 335 | - | ||
| 336 | - final painter = TextPainter( | ||
| 337 | - text: _buildTextSpan(), | ||
| 338 | - textDirection: Directionality.of(context), | ||
| 339 | - textScaler: MediaQuery.textScalerOf(context), | ||
| 340 | - )..layout(maxWidth: constraints.maxWidth); | ||
| 341 | - final linkStart = text.length; | ||
| 342 | - final linkBoxes = painter.getBoxesForSelection( | ||
| 343 | - TextSelection( | ||
| 344 | - baseOffset: linkStart, | ||
| 345 | - extentOffset: linkStart + linkText.length, | ||
| 346 | - ), | ||
| 347 | - ); | ||
| 348 | - | ||
| 349 | - if (linkBoxes.any( | ||
| 350 | - (box) => box.toRect().inflate(10).contains(details.localPosition), | ||
| 351 | - )) { | ||
| 352 | - onLinkTap!.call(); | ||
| 353 | - } | ||
| 354 | - } | ||
| 355 | - | ||
| 356 | @override | 359 | @override |
| 357 | Widget build(BuildContext context) { | 360 | Widget build(BuildContext context) { |
| 358 | return Row( | 361 | return Row( |
| 359 | crossAxisAlignment: CrossAxisAlignment.start, | 362 | crossAxisAlignment: CrossAxisAlignment.start, |
| 360 | children: [ | 363 | children: [ |
| 361 | Text( | 364 | Text( |
| 362 | - prefix, | 365 | + widget.prefix, |
| 363 | style: const TextStyle( | 366 | style: const TextStyle( |
| 364 | color: PurchaseColors.subtitle, | 367 | color: PurchaseColors.subtitle, |
| 365 | fontSize: 12, | 368 | fontSize: 12, |
| @@ -367,17 +370,9 @@ class _LegalText extends StatelessWidget { | @@ -367,17 +370,9 @@ class _LegalText extends StatelessWidget { | ||
| 367 | ), | 370 | ), |
| 368 | ), | 371 | ), |
| 369 | Expanded( | 372 | Expanded( |
| 370 | - child: LayoutBuilder( | ||
| 371 | - builder: (context, constraints) => GestureDetector( | ||
| 372 | - behavior: HitTestBehavior.opaque, | ||
| 373 | - onTapUp: linkText == null || onLinkTap == null | ||
| 374 | - ? null | ||
| 375 | - : (details) => _handleTapUp(context, constraints, details), | ||
| 376 | - child: Text.rich( | ||
| 377 | - _buildTextSpan(), | ||
| 378 | - textScaler: MediaQuery.textScalerOf(context), | ||
| 379 | - ), | ||
| 380 | - ), | 373 | + child: Text.rich( |
| 374 | + _buildTextSpan(), | ||
| 375 | + textScaler: MediaQuery.textScalerOf(context), | ||
| 381 | ), | 376 | ), |
| 382 | ), | 377 | ), |
| 383 | ], | 378 | ], |
| @@ -666,7 +666,7 @@ | @@ -666,7 +666,7 @@ | ||
| 666 | "premiumActivatedContinue": "Continue", | 666 | "premiumActivatedContinue": "Continue", |
| 667 | "purchaseHeroTitle": "Unlock Pro, Care Better", | 667 | "purchaseHeroTitle": "Unlock Pro, Care Better", |
| 668 | "purchaseBenefitsTitle": "Unlock All Pro Benefits", | 668 | "purchaseBenefitsTitle": "Unlock All Pro Benefits", |
| 669 | - "purchaseUnlockNow": "Unlock", | 669 | + "purchaseUnlockNow": "Next", |
| 670 | "purchaseRestore": "Restore", | 670 | "purchaseRestore": "Restore", |
| 671 | "purchaseTermsOfService": "Terms of Service", | 671 | "purchaseTermsOfService": "Terms of Service", |
| 672 | "purchasePrivacyPolicy": "Privacy Policy", | 672 | "purchasePrivacyPolicy": "Privacy Policy", |
| @@ -1065,4 +1065,4 @@ | @@ -1065,4 +1065,4 @@ | ||
| 1065 | } | 1065 | } |
| 1066 | }, | 1066 | }, |
| 1067 | "updatePassword": "Update password" | 1067 | "updatePassword": "Update password" |
| 1068 | -} | ||
| 1068 | +} |
| @@ -1926,7 +1926,7 @@ class AppLocalizationsEn extends AppLocalizations { | @@ -1926,7 +1926,7 @@ class AppLocalizationsEn extends AppLocalizations { | ||
| 1926 | String get purchaseBenefitsTitle => 'Unlock All Pro Benefits'; | 1926 | String get purchaseBenefitsTitle => 'Unlock All Pro Benefits'; |
| 1927 | 1927 | ||
| 1928 | @override | 1928 | @override |
| 1929 | - String get purchaseUnlockNow => 'Unlock'; | 1929 | + String get purchaseUnlockNow => 'Next'; |
| 1930 | 1930 | ||
| 1931 | @override | 1931 | @override |
| 1932 | String get purchaseRestore => 'Restore'; | 1932 | String get purchaseRestore => 'Restore'; |
-
Please register or login to post a comment