membership_offer_view.dart 8.28 KB
import 'package:doublefeel_flutter/app/modules/membership_offer/controllers/membership_offer_controller.dart';
import 'package:doublefeel_flutter/app/routes/app_pages.dart';
import 'package:doublefeel_flutter/core/theme/app_theme.dart';
import 'package:doublefeel_flutter/data/models/pay/pay_models.dart';
import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
import 'package:doublefeel_flutter/core/platform/pigeon_api_facade.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:lottie/lottie.dart';

import '../../user_onboarding/widget/guide_common_scaffold.dart';
import '../../user_onboarding/widget/onboarding_common_widgets.dart';

class MembershipOfferView extends GetView<MembershipOfferController> {
  const MembershipOfferView({super.key});

  @override
  Widget build(BuildContext context) {
    final l10n = context.l10n;
    return PopScope(
        canPop: !controller.isFromOnboard,
        onPopInvokedWithResult: (didPop, _) {
          if (!didPop) {
            controller.onBackPressed();
          }
        },
        child: GuideCommonScaffold(
          showGradientBg: true,
          onBackPressed: () {
            controller.onBackPressed();
          },
          backIcon: 'assets/images/common/ic_close.png',
          bottom: OnboardingBottomButton(
            label: controller.isFromOnboard
                ? l10n.continueButton
                : l10n.freeRedemptionOffer,
            enabled: true,
            onPressed: () {
              controller.unlock();
            },
          ),
          child: Column(
            children: [
              Expanded(
                child: SingleChildScrollView(
                  physics: const NeverScrollableScrollPhysics(),
                  padding: EdgeInsets.fromLTRB(
                    0,
                    MediaQuery.paddingOf(context).top + 4,
                    0,
                    0,
                  ),
                  child: Stack(
                    children: [
                      IgnorePointer(
                        child: Lottie.asset(
                            'assets/lottie/scatter_flowers.json',
                            width: Get.width),
                      ),
                      Column(
                        children: [
                          Padding(
                            padding: const EdgeInsets.symmetric(horizontal: 16),
                            child: Column(
                              children: [
                                SizedBox(height: 48),
                                OnboardingTitleText(l10n.onboardingMemberTitle),
                                const SizedBox(height: 12),
                                OnboardingBodyText(
                                  l10n.onboardingMemberBody,
                                  fontSize: 14,
                                ),
                              ],
                            ),
                          ),
                          const SizedBox(height: 12),
                          Image.asset(
                              'assets/images/user_onboarding/ic_membership_box.png'),
                          const SizedBox(height: 4),
                          Obx(() {
                            final yearInfo =
                                controller.yearlyProductAppleInfo.value;
                            final yearProduct = controller.yearlyProduct.value;

                            return yearInfo == null || yearProduct == null
                                ? const SizedBox(
                                    child: CircularProgressIndicator())
                                : Column(
                                    children: [
                                      Text(
                                        context.l10n.originalPricePerYear(
                                            _originDisplayPrice(yearInfo)),
                                        textAlign: TextAlign.center,
                                        style: const TextStyle(
                                          color: Color(0xFF78787D),
                                          fontSize: 16,
                                          decoration:
                                              TextDecoration.lineThrough,
                                          decorationColor: Color(0xFF78787D),
                                          letterSpacing: 0,
                                        ),
                                      ),
                                      const SizedBox(height: 6),
                                      Text(
                                        _displayPrice(yearInfo),
                                        textAlign: TextAlign.center,
                                        style: TextStyle(
                                          color: context.colors.primary,
                                          fontSize: 28,
                                          fontWeight: FontWeight.w600,
                                          letterSpacing: 0,
                                        ),
                                      ),
                                      const SizedBox(height: 6),
                                      Text(
                                        _planSubtitle(yearProduct, yearInfo),
                                        textAlign: TextAlign.center,
                                        style: const TextStyle(
                                          color: Color(0xFF78787D),
                                          fontSize: 12,
                                          letterSpacing: 0,
                                        ),
                                      ),
                                    ],
                                  );
                          }),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
              GestureDetector(
                behavior: HitTestBehavior.opaque,
                onTap: () {
                  var arguments = {};
                  if (controller.isFromOnboard) {
                    arguments['from'] = 'onboarding';
                    arguments['is_membership_offer'] = true;
                  } else {
                    arguments['channel_type'] =
                        Get.arguments?['channel_type'] ?? '';
                  }
                  Get.offNamed(Routes.PURCHASE, arguments: arguments);
                },
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                    vertical: 12,
                    horizontal: 24,
                  ),
                  child: Text(
                    l10n.onboardingMemberAllOptions,
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      color: context.colors.textPrimary,
                      fontSize: 12,
                      decoration: TextDecoration.underline,
                      decorationColor: context.colors.textPrimary,
                      letterSpacing: 0,
                    ),
                  ),
                ),
              ),
              const SizedBox(height: 140),
            ],
          ),
        ));
  }

  String _originDisplayPrice(AppleProductInfo appleInfo) {
    final actual =
        appleInfo.price > 0 ? appleInfo.price : appleInfo.originPrice;
    final inflated = actual / 100.0 * 1.2;
    // 保留两位小数,单位与 currencyCode 一致
    return '${appleInfo.currencyCode}${inflated.toStringAsFixed(2)}';
  }

  String _displayPrice(AppleProductInfo appleInfo) {
    final price = appleInfo.price;
    if (price > 0) {
      final priceDescription = appleInfo.priceDescription.trim();
      if (priceDescription.isNotEmpty) {
        return priceDescription;
      }
    }
    return appleInfo.originPriceDescription;
  }

  String? _nonEmpty(String? value) {
    final trimmed = value?.trim();
    if (trimmed == null || trimmed.isEmpty) return null;
    return trimmed;
  }

  String _planSubtitle(PayProduct product, AppleProductInfo? appleInfo) {
    if (product.content?.isYearProduct() != true) {
      return _nonEmpty(product.content?.description) ?? '';
    }

    final unitPrice = _nonEmpty(appleInfo?.unitPrice);
    return unitPrice == null ? '' : l10n.purchaseMonthlyUnitPrice(unitPrice);
  }
}