ente/mobile/lib/ui/payment/subscription_plan_widget.dart
Neeraj Gupta 3ac937a244 move
2025-03-05 12:00:02 +05:30

213 lines
7.0 KiB
Dart

import "package:flutter/foundation.dart";
import 'package:flutter/material.dart';
import "package:flutter/scheduler.dart";
import "package:flutter_animate/flutter_animate.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/service_locator.dart";
import "package:photos/theme/colors.dart";
import "package:photos/theme/ente_theme.dart";
import 'package:photos/utils/standalone/data.dart';
class SubscriptionPlanWidget extends StatefulWidget {
const SubscriptionPlanWidget({
super.key,
required this.storage,
required this.price,
required this.period,
required this.isOnboarding,
this.isActive = false,
this.isPopular = false,
});
final int storage;
final String price;
final String period;
final bool isActive;
final bool isPopular;
final bool isOnboarding;
@override
State<SubscriptionPlanWidget> createState() => _SubscriptionPlanWidgetState();
}
class _SubscriptionPlanWidgetState extends State<SubscriptionPlanWidget> {
late final PlatformDispatcher _platformDispatcher;
@override
void initState() {
super.initState();
_platformDispatcher = SchedulerBinding.instance.platformDispatcher;
}
@override
Widget build(BuildContext context) {
final brightness = _platformDispatcher.platformBrightness;
final numAndUnit = convertBytesToNumberAndUnit(widget.storage);
final String storageValue = numAndUnit.$1.toString();
final String storageUnit = numAndUnit.$2;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: Container(
decoration: BoxDecoration(
color: backgroundElevated2Light,
borderRadius: BorderRadius.circular(8),
border: widget.isActive
? Border.all(
color: getEnteColorScheme(context).primary700,
width: brightness == Brightness.dark ? 1.5 : 1,
strokeAlign: BorderSide.strokeAlignInside,
)
: null,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
offset: const Offset(0, 4),
blurRadius: 4,
),
],
),
child: Stack(
children: [
widget.isActive && !widget.isOnboarding
? Positioned(
top: 0,
right: 0,
child: ClipRRect(
borderRadius: const BorderRadius.only(
topRight: Radius.circular(8),
),
child: Image.asset(
"assets/active_subscription.png",
),
),
)
: widget.isPopular
? ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8),
),
child: Image.asset(
"assets/popular_subscription.png",
),
)
: const SizedBox.shrink(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
RichText(
text: TextSpan(
children: [
TextSpan(
text: storageValue,
style: const TextStyle(
fontSize: 40,
fontWeight: FontWeight.w600,
color: textBaseLight,
),
),
WidgetSpan(
child: Transform.translate(
offset: const Offset(2, -16),
child: Text(
storageUnit,
style: getEnteTextTheme(context).h3.copyWith(
color: textMutedLight,
),
),
),
),
],
),
),
_Price(price: widget.price, period: widget.period),
],
),
),
],
),
),
);
}
}
class _Price extends StatelessWidget {
final String price;
final String period;
const _Price({required this.price, required this.period});
@override
Widget build(BuildContext context) {
final textTheme = getEnteTextTheme(context);
if (price.isEmpty) {
return Text(
"Free",
style: textTheme.largeBold.copyWith(color: textBaseLight),
);
}
if (period == "month") {
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
price + ' / ' + S.of(context).month,
style: textTheme.largeBold.copyWith(color: textBaseLight),
)
.animate(delay: const Duration(milliseconds: 100))
.fadeIn(duration: const Duration(milliseconds: 250)),
],
);
} else if (period == "year") {
final currencySymbol = price[0];
final priceWithoutCurrency = price.substring(1);
final priceDouble = double.parse(priceWithoutCurrency);
final pricePerMonth = priceDouble / 12;
String pricePerMonthString = pricePerMonth.toStringAsFixed(2);
if (pricePerMonthString.endsWith(".00")) {
pricePerMonthString =
pricePerMonthString.substring(0, pricePerMonthString.length - 3);
}
final bool isPlayStore = updateService.isPlayStoreFlavor();
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (isPlayStore)
Text(
currencySymbol +
pricePerMonthString +
' / ' +
S.of(context).month,
style: textTheme.largeBold.copyWith(color: textBaseLight),
),
if (isPlayStore)
Text(
price + " / " + S.of(context).yearShort,
style: textTheme.small.copyWith(color: textFaintLight),
),
if (!isPlayStore)
Text(
currencySymbol +
pricePerMonthString +
' / ' +
S.of(context).month,
style: textTheme.largeBold.copyWith(color: textBaseLight),
),
if (!isPlayStore)
Text(
price + " / " + S.of(context).yearShort,
style: textTheme.small.copyWith(color: textFaintLight),
),
],
)
.animate(delay: const Duration(milliseconds: 100))
.fadeIn(duration: const Duration(milliseconds: 250));
} else {
assert(false, "Invalid period: $period");
return const Text("");
}
}
}