Showing
6 changed files
with
288 additions
and
219 deletions
| @@ -73,7 +73,7 @@ class AppReviewPromptLogic { | @@ -73,7 +73,7 @@ class AppReviewPromptLogic { | ||
| 73 | final result = await showDialog<AppReviewPromptResult>( | 73 | final result = await showDialog<AppReviewPromptResult>( |
| 74 | context: context, | 74 | context: context, |
| 75 | barrierColor: Colors.black.withValues(alpha: 0.7), | 75 | barrierColor: Colors.black.withValues(alpha: 0.7), |
| 76 | - barrierDismissible: false, | 76 | + barrierDismissible: true, |
| 77 | builder: (_) => const AppReviewFeedbackDialog(), | 77 | builder: (_) => const AppReviewFeedbackDialog(), |
| 78 | ); | 78 | ); |
| 79 | 79 |
| @@ -81,98 +81,95 @@ class _ReviewPromptCard extends StatelessWidget { | @@ -81,98 +81,95 @@ class _ReviewPromptCard extends StatelessWidget { | ||
| 81 | @override | 81 | @override |
| 82 | Widget build(BuildContext context) { | 82 | Widget build(BuildContext context) { |
| 83 | final isFeedback = height > 400; | 83 | final isFeedback = height > 400; |
| 84 | - return PopScope( | ||
| 85 | - canPop: false, | ||
| 86 | - child: Align( | ||
| 87 | - alignment: _dialogAlignment, | ||
| 88 | - child: Material( | ||
| 89 | - color: Colors.transparent, | ||
| 90 | - child: Container( | ||
| 91 | - width: _cardWidth, | ||
| 92 | - height: height, | ||
| 93 | - clipBehavior: Clip.antiAlias, | ||
| 94 | - decoration: BoxDecoration( | ||
| 95 | - borderRadius: BorderRadius.circular(16), | ||
| 96 | - gradient: const LinearGradient( | ||
| 97 | - begin: Alignment.topCenter, | ||
| 98 | - end: Alignment.bottomCenter, | ||
| 99 | - colors: [ | ||
| 100 | - Color(0xFFE6DBFF), | ||
| 101 | - Color(0xFFEDE4FF), | ||
| 102 | - Color(0xFFEEE6FF), | ||
| 103 | - Color(0xFFF9F6FF), | ||
| 104 | - ], | ||
| 105 | - stops: [0, 0.25, 0.75, 1], | ||
| 106 | - ), | 84 | + return Align( |
| 85 | + alignment: _dialogAlignment, | ||
| 86 | + child: Material( | ||
| 87 | + color: Colors.transparent, | ||
| 88 | + child: Container( | ||
| 89 | + width: _cardWidth, | ||
| 90 | + height: height, | ||
| 91 | + clipBehavior: Clip.antiAlias, | ||
| 92 | + decoration: BoxDecoration( | ||
| 93 | + borderRadius: BorderRadius.circular(16), | ||
| 94 | + gradient: const LinearGradient( | ||
| 95 | + begin: Alignment.topCenter, | ||
| 96 | + end: Alignment.bottomCenter, | ||
| 97 | + colors: [ | ||
| 98 | + Color(0xFFE6DBFF), | ||
| 99 | + Color(0xFFEDE4FF), | ||
| 100 | + Color(0xFFEEE6FF), | ||
| 101 | + Color(0xFFF9F6FF), | ||
| 102 | + ], | ||
| 103 | + stops: [0, 0.25, 0.75, 1], | ||
| 107 | ), | 104 | ), |
| 108 | - child: Stack( | ||
| 109 | - children: [ | ||
| 110 | - Positioned( | ||
| 111 | - top: 0, | ||
| 112 | - left: 0, | ||
| 113 | - right: 0, | ||
| 114 | - height: _illustrationHeight, | ||
| 115 | - child: Image.asset( | ||
| 116 | - illustrationAsset, | ||
| 117 | - fit: BoxFit.cover, | ||
| 118 | - ), | ||
| 119 | - ), | ||
| 120 | - Positioned( | ||
| 121 | - top: isFeedback ? 162 : 163, | ||
| 122 | - left: 38, | ||
| 123 | - right: 38, | ||
| 124 | - child: Text( | ||
| 125 | - title, | ||
| 126 | - textAlign: TextAlign.center, | ||
| 127 | - style: const TextStyle( | ||
| 128 | - color: _h1, | ||
| 129 | - fontSize: 18, | ||
| 130 | - height: 1.35, | ||
| 131 | - fontWeight: FontWeight.w600, | ||
| 132 | - ), | ||
| 133 | - ), | ||
| 134 | - ), | ||
| 135 | - Positioned( | ||
| 136 | - top: isFeedback ? 222 : 195, | ||
| 137 | - left: 20, | ||
| 138 | - right: 20, | ||
| 139 | - child: Text( | ||
| 140 | - message, | ||
| 141 | - textAlign: TextAlign.center, | ||
| 142 | - style: const TextStyle( | ||
| 143 | - color: _h2, | ||
| 144 | - fontSize: 14, | ||
| 145 | - height: 1.35, | ||
| 146 | - fontWeight: FontWeight.w400, | ||
| 147 | - ), | ||
| 148 | - ), | 105 | + ), |
| 106 | + child: Stack( | ||
| 107 | + children: [ | ||
| 108 | + Positioned( | ||
| 109 | + top: 0, | ||
| 110 | + left: 0, | ||
| 111 | + right: 0, | ||
| 112 | + height: _illustrationHeight, | ||
| 113 | + child: Image.asset( | ||
| 114 | + illustrationAsset, | ||
| 115 | + fit: BoxFit.cover, | ||
| 149 | ), | 116 | ), |
| 150 | - Positioned( | ||
| 151 | - top: isFeedback ? 305 : 260, | ||
| 152 | - left: 40, | ||
| 153 | - right: 40, | ||
| 154 | - child: _PromptButton( | ||
| 155 | - emoji: primaryEmoji, | ||
| 156 | - text: primaryText, | ||
| 157 | - textColor: Colors.white, | 117 | + ), |
| 118 | + Positioned( | ||
| 119 | + top: isFeedback ? 162 : 163, | ||
| 120 | + left: 38, | ||
| 121 | + right: 38, | ||
| 122 | + child: Text( | ||
| 123 | + title, | ||
| 124 | + textAlign: TextAlign.center, | ||
| 125 | + style: const TextStyle( | ||
| 126 | + color: _h1, | ||
| 127 | + fontSize: 18, | ||
| 128 | + height: 1.35, | ||
| 158 | fontWeight: FontWeight.w600, | 129 | fontWeight: FontWeight.w600, |
| 159 | - backgroundColor: _brandColor, | ||
| 160 | - onTap: onPrimaryTap, | ||
| 161 | ), | 130 | ), |
| 162 | ), | 131 | ), |
| 163 | - Positioned( | ||
| 164 | - top: isFeedback ? 357 : 312, | ||
| 165 | - left: 40, | ||
| 166 | - right: 40, | ||
| 167 | - child: _PromptButton( | ||
| 168 | - text: secondaryText, | ||
| 169 | - textColor: _h2, | 132 | + ), |
| 133 | + Positioned( | ||
| 134 | + top: isFeedback ? 222 : 195, | ||
| 135 | + left: 20, | ||
| 136 | + right: 20, | ||
| 137 | + child: Text( | ||
| 138 | + message, | ||
| 139 | + textAlign: TextAlign.center, | ||
| 140 | + style: const TextStyle( | ||
| 141 | + color: _h2, | ||
| 142 | + fontSize: 14, | ||
| 143 | + height: 1.35, | ||
| 170 | fontWeight: FontWeight.w400, | 144 | fontWeight: FontWeight.w400, |
| 171 | - onTap: onSecondaryTap, | ||
| 172 | ), | 145 | ), |
| 173 | ), | 146 | ), |
| 174 | - ], | ||
| 175 | - ), | 147 | + ), |
| 148 | + Positioned( | ||
| 149 | + top: isFeedback ? 305 : 260, | ||
| 150 | + left: 40, | ||
| 151 | + right: 40, | ||
| 152 | + child: _PromptButton( | ||
| 153 | + emoji: primaryEmoji, | ||
| 154 | + text: primaryText, | ||
| 155 | + textColor: Colors.white, | ||
| 156 | + fontWeight: FontWeight.w600, | ||
| 157 | + backgroundColor: _brandColor, | ||
| 158 | + onTap: onPrimaryTap, | ||
| 159 | + ), | ||
| 160 | + ), | ||
| 161 | + Positioned( | ||
| 162 | + top: isFeedback ? 357 : 312, | ||
| 163 | + left: 40, | ||
| 164 | + right: 40, | ||
| 165 | + child: _PromptButton( | ||
| 166 | + text: secondaryText, | ||
| 167 | + textColor: _h2, | ||
| 168 | + fontWeight: FontWeight.w400, | ||
| 169 | + onTap: onSecondaryTap, | ||
| 170 | + ), | ||
| 171 | + ), | ||
| 172 | + ], | ||
| 176 | ), | 173 | ), |
| 177 | ), | 174 | ), |
| 178 | ), | 175 | ), |
| @@ -347,7 +347,7 @@ class _FriendsHeader extends StatelessWidget { | @@ -347,7 +347,7 @@ class _FriendsHeader extends StatelessWidget { | ||
| 347 | const Spacer(), | 347 | const Spacer(), |
| 348 | IconButton( | 348 | IconButton( |
| 349 | onPressed: () { | 349 | onPressed: () { |
| 350 | - _navigatorToPrivacySettings(); | 350 | + _navigatorToPrivacySettings(context); |
| 351 | }, | 351 | }, |
| 352 | icon: Image.asset( | 352 | icon: Image.asset( |
| 353 | R.assetsImagesSettings, | 353 | R.assetsImagesSettings, |
| @@ -364,7 +364,7 @@ class _FriendsHeader extends StatelessWidget { | @@ -364,7 +364,7 @@ class _FriendsHeader extends StatelessWidget { | ||
| 364 | } | 364 | } |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | -_navigatorToPrivacySettings() { | 367 | +_navigatorToPrivacySettings(BuildContext context) { |
| 368 | Get.toNamed(Routes.PRIVACY_SETTINGS); | 368 | Get.toNamed(Routes.PRIVACY_SETTINGS); |
| 369 | } | 369 | } |
| 370 | 370 |
| @@ -419,6 +419,57 @@ class _LegalText extends StatelessWidget { | @@ -419,6 +419,57 @@ class _LegalText extends StatelessWidget { | ||
| 419 | final String? linkSuffix; | 419 | final String? linkSuffix; |
| 420 | final VoidCallback? onLinkTap; | 420 | final VoidCallback? onLinkTap; |
| 421 | 421 | ||
| 422 | + static const _baseStyle = TextStyle( | ||
| 423 | + color: PurchaseColors.subtitle, | ||
| 424 | + fontSize: 12, | ||
| 425 | + height: 1.4, | ||
| 426 | + ); | ||
| 427 | + | ||
| 428 | + static const _linkStyle = TextStyle( | ||
| 429 | + color: Color(0xFF845EEE), | ||
| 430 | + fontWeight: FontWeight.w500, | ||
| 431 | + decoration: TextDecoration.underline, | ||
| 432 | + decorationColor: Color(0xFF845EEE), | ||
| 433 | + ); | ||
| 434 | + | ||
| 435 | + TextSpan _buildTextSpan() => TextSpan( | ||
| 436 | + style: _baseStyle, | ||
| 437 | + children: [ | ||
| 438 | + TextSpan(text: text), | ||
| 439 | + if (linkText case final linkText?) | ||
| 440 | + TextSpan(text: linkText, style: _linkStyle), | ||
| 441 | + if (linkSuffix case final linkSuffix?) TextSpan(text: linkSuffix), | ||
| 442 | + ], | ||
| 443 | + ); | ||
| 444 | + | ||
| 445 | + void _handleTapUp( | ||
| 446 | + BuildContext context, | ||
| 447 | + BoxConstraints constraints, | ||
| 448 | + TapUpDetails details, | ||
| 449 | + ) { | ||
| 450 | + final linkText = this.linkText; | ||
| 451 | + if (linkText == null || onLinkTap == null) return; | ||
| 452 | + | ||
| 453 | + final painter = TextPainter( | ||
| 454 | + text: _buildTextSpan(), | ||
| 455 | + textDirection: Directionality.of(context), | ||
| 456 | + textScaler: MediaQuery.textScalerOf(context), | ||
| 457 | + )..layout(maxWidth: constraints.maxWidth); | ||
| 458 | + final linkStart = text.length; | ||
| 459 | + final linkBoxes = painter.getBoxesForSelection( | ||
| 460 | + TextSelection( | ||
| 461 | + baseOffset: linkStart, | ||
| 462 | + extentOffset: linkStart + linkText.length, | ||
| 463 | + ), | ||
| 464 | + ); | ||
| 465 | + | ||
| 466 | + if (linkBoxes.any( | ||
| 467 | + (box) => box.toRect().inflate(10).contains(details.localPosition), | ||
| 468 | + )) { | ||
| 469 | + onLinkTap!.call(); | ||
| 470 | + } | ||
| 471 | + } | ||
| 472 | + | ||
| 422 | @override | 473 | @override |
| 423 | Widget build(BuildContext context) { | 474 | Widget build(BuildContext context) { |
| 424 | return Row( | 475 | return Row( |
| @@ -433,38 +484,16 @@ class _LegalText extends StatelessWidget { | @@ -433,38 +484,16 @@ class _LegalText extends StatelessWidget { | ||
| 433 | ), | 484 | ), |
| 434 | ), | 485 | ), |
| 435 | Expanded( | 486 | Expanded( |
| 436 | - child: Text.rich( | ||
| 437 | - TextSpan( | ||
| 438 | - children: [ | ||
| 439 | - TextSpan(text: text), | ||
| 440 | - if (linkText case final linkText?) | ||
| 441 | - WidgetSpan( | ||
| 442 | - alignment: PlaceholderAlignment.baseline, | ||
| 443 | - baseline: TextBaseline.alphabetic, | ||
| 444 | - child: GestureDetector( | ||
| 445 | - behavior: HitTestBehavior.opaque, | ||
| 446 | - onTap: onLinkTap, | ||
| 447 | - child: Text( | ||
| 448 | - linkText, | ||
| 449 | - style: const TextStyle( | ||
| 450 | - color: Color(0xFF845EEE), | ||
| 451 | - fontSize: 12, | ||
| 452 | - height: 1.4, | ||
| 453 | - fontWeight: FontWeight.w500, | ||
| 454 | - decoration: TextDecoration.underline, | ||
| 455 | - decorationColor: Color(0xFF845EEE), | ||
| 456 | - ), | ||
| 457 | - ), | ||
| 458 | - ), | ||
| 459 | - ), | ||
| 460 | - if (linkSuffix case final linkSuffix?) | ||
| 461 | - TextSpan(text: linkSuffix), | ||
| 462 | - ], | ||
| 463 | - ), | ||
| 464 | - style: const TextStyle( | ||
| 465 | - color: PurchaseColors.subtitle, | ||
| 466 | - fontSize: 12, | ||
| 467 | - height: 1.4, | 487 | + child: LayoutBuilder( |
| 488 | + builder: (context, constraints) => GestureDetector( | ||
| 489 | + behavior: HitTestBehavior.opaque, | ||
| 490 | + onTapUp: linkText == null || onLinkTap == null | ||
| 491 | + ? null | ||
| 492 | + : (details) => _handleTapUp(context, constraints, details), | ||
| 493 | + child: Text.rich( | ||
| 494 | + _buildTextSpan(), | ||
| 495 | + textScaler: MediaQuery.textScalerOf(context), | ||
| 496 | + ), | ||
| 468 | ), | 497 | ), |
| 469 | ), | 498 | ), |
| 470 | ), | 499 | ), |
| @@ -38,13 +38,15 @@ class PurchaseView extends GetView<PurchaseController> { | @@ -38,13 +38,15 @@ class PurchaseView extends GetView<PurchaseController> { | ||
| 38 | child: SingleChildScrollView( | 38 | child: SingleChildScrollView( |
| 39 | controller: controller.scrollController, | 39 | controller: controller.scrollController, |
| 40 | physics: const ClampingScrollPhysics(), | 40 | physics: const ClampingScrollPhysics(), |
| 41 | - padding: const EdgeInsets.only(bottom: 170), | 41 | + padding: EdgeInsets.only( |
| 42 | + bottom: 170 + MediaQuery.paddingOf(context).bottom, | ||
| 43 | + ), | ||
| 42 | child: Column( | 44 | child: Column( |
| 43 | crossAxisAlignment: CrossAxisAlignment.start, | 45 | crossAxisAlignment: CrossAxisAlignment.start, |
| 44 | children: [ | 46 | children: [ |
| 45 | const _HeroHeader(), | 47 | const _HeroHeader(), |
| 46 | Padding( | 48 | Padding( |
| 47 | - padding: EdgeInsets.only(left: 18, top: 9.h), | 49 | + padding: EdgeInsets.only(left: 18, top: 9.h), |
| 48 | child: Text( | 50 | child: Text( |
| 49 | context.l10n.purchaseHeroTitle, | 51 | context.l10n.purchaseHeroTitle, |
| 50 | style: const TextStyle( | 52 | style: const TextStyle( |
| @@ -299,6 +301,57 @@ class _LegalText extends StatelessWidget { | @@ -299,6 +301,57 @@ class _LegalText extends StatelessWidget { | ||
| 299 | final String? linkSuffix; | 301 | final String? linkSuffix; |
| 300 | final VoidCallback? onLinkTap; | 302 | final VoidCallback? onLinkTap; |
| 301 | 303 | ||
| 304 | + static const _baseStyle = TextStyle( | ||
| 305 | + color: PurchaseColors.subtitle, | ||
| 306 | + fontSize: 12, | ||
| 307 | + height: 1.4, | ||
| 308 | + ); | ||
| 309 | + | ||
| 310 | + static const _linkStyle = TextStyle( | ||
| 311 | + color: Color(0xFF845EEE), | ||
| 312 | + fontWeight: FontWeight.w500, | ||
| 313 | + decoration: TextDecoration.underline, | ||
| 314 | + decorationColor: Color(0xFF845EEE), | ||
| 315 | + ); | ||
| 316 | + | ||
| 317 | + TextSpan _buildTextSpan() => TextSpan( | ||
| 318 | + style: _baseStyle, | ||
| 319 | + children: [ | ||
| 320 | + TextSpan(text: text), | ||
| 321 | + if (linkText case final linkText?) | ||
| 322 | + TextSpan(text: linkText, style: _linkStyle), | ||
| 323 | + if (linkSuffix case final linkSuffix?) TextSpan(text: linkSuffix), | ||
| 324 | + ], | ||
| 325 | + ); | ||
| 326 | + | ||
| 327 | + void _handleTapUp( | ||
| 328 | + BuildContext context, | ||
| 329 | + BoxConstraints constraints, | ||
| 330 | + TapUpDetails details, | ||
| 331 | + ) { | ||
| 332 | + final linkText = this.linkText; | ||
| 333 | + if (linkText == null || onLinkTap == null) return; | ||
| 334 | + | ||
| 335 | + final painter = TextPainter( | ||
| 336 | + text: _buildTextSpan(), | ||
| 337 | + textDirection: Directionality.of(context), | ||
| 338 | + textScaler: MediaQuery.textScalerOf(context), | ||
| 339 | + )..layout(maxWidth: constraints.maxWidth); | ||
| 340 | + final linkStart = text.length; | ||
| 341 | + final linkBoxes = painter.getBoxesForSelection( | ||
| 342 | + TextSelection( | ||
| 343 | + baseOffset: linkStart, | ||
| 344 | + extentOffset: linkStart + linkText.length, | ||
| 345 | + ), | ||
| 346 | + ); | ||
| 347 | + | ||
| 348 | + if (linkBoxes.any( | ||
| 349 | + (box) => box.toRect().inflate(10).contains(details.localPosition), | ||
| 350 | + )) { | ||
| 351 | + onLinkTap!.call(); | ||
| 352 | + } | ||
| 353 | + } | ||
| 354 | + | ||
| 302 | @override | 355 | @override |
| 303 | Widget build(BuildContext context) { | 356 | Widget build(BuildContext context) { |
| 304 | return Row( | 357 | return Row( |
| @@ -313,38 +366,16 @@ class _LegalText extends StatelessWidget { | @@ -313,38 +366,16 @@ class _LegalText extends StatelessWidget { | ||
| 313 | ), | 366 | ), |
| 314 | ), | 367 | ), |
| 315 | Expanded( | 368 | Expanded( |
| 316 | - child: Text.rich( | ||
| 317 | - TextSpan( | ||
| 318 | - children: [ | ||
| 319 | - TextSpan(text: text), | ||
| 320 | - if (linkText case final linkText?) | ||
| 321 | - WidgetSpan( | ||
| 322 | - alignment: PlaceholderAlignment.baseline, | ||
| 323 | - baseline: TextBaseline.alphabetic, | ||
| 324 | - child: GestureDetector( | ||
| 325 | - behavior: HitTestBehavior.opaque, | ||
| 326 | - onTap: onLinkTap, | ||
| 327 | - child: Text( | ||
| 328 | - linkText, | ||
| 329 | - style: const TextStyle( | ||
| 330 | - color: Color(0xFF845EEE), | ||
| 331 | - fontSize: 12, | ||
| 332 | - height: 1.4, | ||
| 333 | - fontWeight: FontWeight.w500, | ||
| 334 | - decoration: TextDecoration.underline, | ||
| 335 | - decorationColor: Color(0xFF845EEE), | ||
| 336 | - ), | ||
| 337 | - ), | ||
| 338 | - ), | ||
| 339 | - ), | ||
| 340 | - if (linkSuffix case final linkSuffix?) | ||
| 341 | - TextSpan(text: linkSuffix), | ||
| 342 | - ], | ||
| 343 | - ), | ||
| 344 | - style: const TextStyle( | ||
| 345 | - color: PurchaseColors.subtitle, | ||
| 346 | - fontSize: 12, | ||
| 347 | - height: 1.4, | 369 | + child: LayoutBuilder( |
| 370 | + builder: (context, constraints) => GestureDetector( | ||
| 371 | + behavior: HitTestBehavior.opaque, | ||
| 372 | + onTapUp: linkText == null || onLinkTap == null | ||
| 373 | + ? null | ||
| 374 | + : (details) => _handleTapUp(context, constraints, details), | ||
| 375 | + child: Text.rich( | ||
| 376 | + _buildTextSpan(), | ||
| 377 | + textScaler: MediaQuery.textScalerOf(context), | ||
| 378 | + ), | ||
| 348 | ), | 379 | ), |
| 349 | ), | 380 | ), |
| 350 | ), | 381 | ), |
| @@ -26,79 +26,91 @@ class PurchaseBottomBar extends StatelessWidget { | @@ -26,79 +26,91 @@ class PurchaseBottomBar extends StatelessWidget { | ||
| 26 | final bottomInset = MediaQuery.paddingOf(context).bottom; | 26 | final bottomInset = MediaQuery.paddingOf(context).bottom; |
| 27 | final buttonWidth = math.min(280.0, MediaQuery.sizeOf(context).width - 74); | 27 | final buttonWidth = math.min(280.0, MediaQuery.sizeOf(context).width - 74); |
| 28 | 28 | ||
| 29 | - return IgnorePointer( | ||
| 30 | - ignoring: loading, | ||
| 31 | - child: Container( | ||
| 32 | - height: 147 + bottomInset, | ||
| 33 | - padding: EdgeInsets.only(bottom: bottomInset), | ||
| 34 | - decoration: const BoxDecoration( | ||
| 35 | - gradient: LinearGradient( | ||
| 36 | - begin: Alignment.topCenter, | ||
| 37 | - end: Alignment.center, | ||
| 38 | - colors: [Color(0x00F5F2FF), PurchaseColors.background], | ||
| 39 | - ), | ||
| 40 | - ), | ||
| 41 | - child: Column( | ||
| 42 | - mainAxisAlignment: MainAxisAlignment.end, | ||
| 43 | - children: [ | ||
| 44 | - SizedBox( | ||
| 45 | - width: buttonWidth, | ||
| 46 | - height: 48, | ||
| 47 | - child: ElevatedButton( | ||
| 48 | - onPressed: onPressed, | ||
| 49 | - style: ElevatedButton.styleFrom( | ||
| 50 | - elevation: 0, | ||
| 51 | - shadowColor: Colors.transparent, | ||
| 52 | - backgroundColor: PurchaseColors.proYellow, | ||
| 53 | - foregroundColor: PurchaseColors.title, | ||
| 54 | - shape: RoundedRectangleBorder( | ||
| 55 | - borderRadius: BorderRadius.circular(24), | ||
| 56 | - ), | ||
| 57 | - textStyle: const TextStyle( | ||
| 58 | - fontSize: 16, | ||
| 59 | - fontWeight: FontWeight.w600, | ||
| 60 | - letterSpacing: 0, | 29 | + return SizedBox( |
| 30 | + height: 147 + bottomInset, | ||
| 31 | + child: Stack( | ||
| 32 | + children: [ | ||
| 33 | + const Positioned.fill( | ||
| 34 | + child: IgnorePointer( | ||
| 35 | + child: DecoratedBox( | ||
| 36 | + decoration: BoxDecoration( | ||
| 37 | + gradient: LinearGradient( | ||
| 38 | + begin: Alignment.topCenter, | ||
| 39 | + end: Alignment.center, | ||
| 40 | + colors: [Color(0x00F5F2FF), PurchaseColors.background], | ||
| 61 | ), | 41 | ), |
| 62 | ), | 42 | ), |
| 63 | - child: loading | ||
| 64 | - ? const SizedBox( | ||
| 65 | - width: 18, | ||
| 66 | - height: 18, | ||
| 67 | - child: CircularProgressIndicator( | ||
| 68 | - strokeWidth: 2, | ||
| 69 | - color: PurchaseColors.title, | ||
| 70 | - ), | ||
| 71 | - ) | ||
| 72 | - : Text(label), | ||
| 73 | ), | 43 | ), |
| 74 | ), | 44 | ), |
| 75 | - const SizedBox(height: 12), | ||
| 76 | - Row( | ||
| 77 | - mainAxisAlignment: MainAxisAlignment.center, | ||
| 78 | - children: [ | ||
| 79 | - _BottomLink( | ||
| 80 | - label: context.l10n.purchaseTermsOfService, | ||
| 81 | - onTap: onTermsTap, | ||
| 82 | - ), | ||
| 83 | - const Padding( | ||
| 84 | - padding: EdgeInsets.symmetric(horizontal: 8), | ||
| 85 | - child: Text( | ||
| 86 | - '|', | ||
| 87 | - style: TextStyle( | ||
| 88 | - color: PurchaseColors.subtitle, | ||
| 89 | - fontSize: 12, | 45 | + ), |
| 46 | + IgnorePointer( | ||
| 47 | + ignoring: loading, | ||
| 48 | + child: Padding( | ||
| 49 | + padding: EdgeInsets.only(bottom: bottomInset), | ||
| 50 | + child: Column( | ||
| 51 | + mainAxisAlignment: MainAxisAlignment.end, | ||
| 52 | + children: [ | ||
| 53 | + SizedBox( | ||
| 54 | + width: buttonWidth, | ||
| 55 | + height: 48, | ||
| 56 | + child: ElevatedButton( | ||
| 57 | + onPressed: onPressed, | ||
| 58 | + style: ElevatedButton.styleFrom( | ||
| 59 | + elevation: 0, | ||
| 60 | + shadowColor: Colors.transparent, | ||
| 61 | + backgroundColor: PurchaseColors.proYellow, | ||
| 62 | + foregroundColor: PurchaseColors.title, | ||
| 63 | + shape: RoundedRectangleBorder( | ||
| 64 | + borderRadius: BorderRadius.circular(24), | ||
| 65 | + ), | ||
| 66 | + textStyle: const TextStyle( | ||
| 67 | + fontSize: 16, | ||
| 68 | + fontWeight: FontWeight.w600, | ||
| 69 | + letterSpacing: 0, | ||
| 70 | + ), | ||
| 71 | + ), | ||
| 72 | + child: loading | ||
| 73 | + ? const SizedBox( | ||
| 74 | + width: 18, | ||
| 75 | + height: 18, | ||
| 76 | + child: CircularProgressIndicator( | ||
| 77 | + strokeWidth: 2, | ||
| 78 | + color: PurchaseColors.title, | ||
| 79 | + ), | ||
| 80 | + ) | ||
| 81 | + : Text(label), | ||
| 90 | ), | 82 | ), |
| 91 | ), | 83 | ), |
| 92 | - ), | ||
| 93 | - _BottomLink( | ||
| 94 | - label: context.l10n.purchasePrivacyPolicy, | ||
| 95 | - onTap: onPrivacyTap, | ||
| 96 | - ), | ||
| 97 | - ], | 84 | + const SizedBox(height: 12), |
| 85 | + Row( | ||
| 86 | + mainAxisAlignment: MainAxisAlignment.center, | ||
| 87 | + children: [ | ||
| 88 | + _BottomLink( | ||
| 89 | + label: context.l10n.purchaseTermsOfService, | ||
| 90 | + onTap: onTermsTap, | ||
| 91 | + ), | ||
| 92 | + const Padding( | ||
| 93 | + padding: EdgeInsets.symmetric(horizontal: 8), | ||
| 94 | + child: Text( | ||
| 95 | + '|', | ||
| 96 | + style: TextStyle( | ||
| 97 | + color: PurchaseColors.subtitle, | ||
| 98 | + fontSize: 12, | ||
| 99 | + ), | ||
| 100 | + ), | ||
| 101 | + ), | ||
| 102 | + _BottomLink( | ||
| 103 | + label: context.l10n.purchasePrivacyPolicy, | ||
| 104 | + onTap: onPrivacyTap, | ||
| 105 | + ), | ||
| 106 | + ], | ||
| 107 | + ), | ||
| 108 | + const SizedBox(height: 18), | ||
| 109 | + ], | ||
| 110 | + ), | ||
| 98 | ), | 111 | ), |
| 99 | - const SizedBox(height: 18), | ||
| 100 | - ], | ||
| 101 | - ), | 112 | + ), |
| 113 | + ], | ||
| 102 | ), | 114 | ), |
| 103 | ); | 115 | ); |
| 104 | } | 116 | } |
-
Please register or login to post a comment