Add initial UI for phone number product page

This commit is contained in:
OmarHatem28 2022-07-01 19:15:07 +02:00
parent 2ed6700b48
commit 57f8ada2b0
8 changed files with 282 additions and 39 deletions

View file

@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
class ServicePlan {
const ServicePlan({
@required this.id,
@required this.duration,
@required this.price,
@required this.quantity,
});
final String id;
final int duration;
final int price;
final int quantity;
@override
bool operator ==(Object other) => other is ServicePlan && other.id == id;
@override
int get hashCode => id.hashCode;
}

View file

@ -67,6 +67,7 @@ import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
import 'package:cake_wallet/src/screens/cake_phone/cake_phone_welcome_page.dart';
import 'package:cake_wallet/src/screens/cake_phone/cake_phone_verification_page.dart';
import 'package:cake_wallet/src/screens/cake_phone/cake_phone_products_page.dart';
import 'package:cake_wallet/src/screens/cake_phone/cake_phone_products/phone_number_product_page.dart';
RouteSettings currentRouteSettings;
@ -427,6 +428,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) => CakePhoneProductsPage(),
);
case Routes.phoneNumberProduct:
return MaterialPageRoute<PhoneNumberProductPage>(
builder: (_) => PhoneNumberProductPage(),
);
default:
return MaterialPageRoute<void>(
builder: (_) => Scaffold(

View file

@ -64,4 +64,5 @@ class Routes {
static const cakePhoneAuth = '/cake_phone_auth';
static const cakePhoneVerification = '/cake_phone_verification';
static const cakePhoneProducts = '/cake_phone_products';
static const phoneNumberProduct = '/phone_number_product';
}

View file

@ -23,7 +23,7 @@ class CakePhoneAuthPage extends BasePage {
fontSize: 22,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: titleColor ?? Theme.of(context).primaryTextTheme.title.color),
color: Theme.of(context).primaryTextTheme.title.color),
);
}
}

View file

@ -0,0 +1,201 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/entities/service_plan.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
class PhoneNumberProductPage extends BasePage {
PhoneNumberProductPage();
@override
Widget body(BuildContext context) => PhoneNumberProductBody();
@override
Widget middle(BuildContext context) {
return Text(
S.of(context).phone_number,
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme.title.color),
);
}
}
class PhoneNumberProductBody extends StatefulWidget {
PhoneNumberProductBody();
@override
PhoneNumberProductBodyState createState() => PhoneNumberProductBodyState();
}
class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
final List<ServicePlan> dummyPlans = [
ServicePlan(id: "1", duration: 1, price: 20, quantity: 30),
ServicePlan(id: "2", duration: 3, price: 10, quantity: 60),
ServicePlan(id: "3", duration: 6, price: 9, quantity: 120),
ServicePlan(id: "4", duration: 12, price: 5, quantity: 200),
];
final int rateInCents = 20;
ServicePlan selectedPlan;
@override
void initState() {
super.initState();
selectedPlan = dummyPlans.first;
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 16),
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.symmetric(horizontal: 24, vertical: 20),
content: Column(
children: [
Text(
S.of(context).initial_service_term,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
color: Theme.of(context).primaryTextTheme.title.color,
fontFamily: 'Lato',
),
),
Padding(
padding: const EdgeInsets.only(top: 8, bottom: 24),
child: Text(
S.of(context).phone_number_promotion_text,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).accentTextTheme.subhead.color,
fontFamily: 'Lato',
),
),
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: dummyPlans.map((e) => planCard(e)).toList(),
),
),
const SizedBox(height: 40),
Text(
S.of(context).free_sms_email_forward,
style: TextStyle(
color: Theme.of(context).accentTextTheme.subhead.color,
),
),
Container(
padding: const EdgeInsets.only(top: 8, bottom: 16),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).accentTextTheme.title.backgroundColor,
))),
child: Text(
"${selectedPlan.quantity}, " +
"${S.of(context).then} " +
"\$${(rateInCents / 100).toStringAsFixed(2)} " +
"${S.of(context).per_message}",
style: TextStyle(
color: Theme.of(context).accentTextTheme.caption.backgroundColor,
),
),
),
],
),
bottomSectionPadding: EdgeInsets.only(bottom: 24, right: 24, left: 24),
bottomSection: Column(
children: <Widget>[
RichText(
text: TextSpan(
children: [
TextSpan(text: "${S.of(context).due_today} "),
TextSpan(
text: "\$35.00 ",
style: TextStyle(fontWeight: FontWeight.w700),
),
],
style: TextStyle(
fontSize: 15,
color: Theme.of(context).accentTextTheme.subhead.color,
fontFamily: 'Lato',
),
),
),
const SizedBox(height: 24),
PrimaryButton(
onPressed: () {},
text: S.of(context).pay_with_cake_phone,
color: Theme.of(context).accentTextTheme.caption.backgroundColor,
textColor: Theme.of(context).primaryTextTheme.title.color,
),
const SizedBox(height: 8),
PrimaryButton(
onPressed: () {},
text: S.of(context).pay_with_xmr,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
),
],
),
),
);
}
Widget planCard(ServicePlan e) {
return GestureDetector(
onTap: () {
if (e != selectedPlan) {
selectedPlan = e;
setState(() {});
}
},
child: Container(
margin: EdgeInsets.symmetric(horizontal: 2),
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 6),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
gradient: selectedPlan == e
? LinearGradient(
colors: [
Theme.of(context).primaryTextTheme.subhead.color,
Theme.of(context).primaryTextTheme.subhead.decorationColor,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
)
: null,
color: selectedPlan == e ? null : Theme.of(context).primaryTextTheme.display3.decorationColor,
),
child: Column(
children: [
Text(
"\$${e.price}/${S.of(context).month}",
style: TextStyle(
fontWeight: FontWeight.w500,
color: selectedPlan == e ? Colors.white : Theme.of(context).primaryTextTheme.title.color,
),
),
Text(
"${e.duration} ${S.of(context).month}",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w500,
color: selectedPlan == e ? Colors.white : Theme.of(context).accentTextTheme.subhead.color,
fontFamily: 'Lato',
),
),
],
),
),
);
}
}

View file

@ -18,7 +18,7 @@ class CakePhoneProductsPage extends BasePage {
fontSize: 22,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: titleColor ?? Theme.of(context).primaryTextTheme.title.color),
color: Theme.of(context).primaryTextTheme.title.color),
);
}
}
@ -48,47 +48,52 @@ class CakePhoneProductsBodyState extends State<CakePhoneProductsBody> {
fontFamily: 'Lato',
),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(24)),
gradient: LinearGradient(
colors: [
Theme.of(context).primaryTextTheme.subhead.color,
Theme.of(context).primaryTextTheme.subhead.decorationColor,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
GestureDetector(
onTap: () {
Navigator.pushNamed(context, Routes.phoneNumberProduct);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(24)),
gradient: LinearGradient(
colors: [
Theme.of(context).primaryTextTheme.subhead.color,
Theme.of(context).primaryTextTheme.subhead.decorationColor,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
padding: const EdgeInsets.all(24),
margin: const EdgeInsets.only(top: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(
S.of(context).phone_number,
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.w700,
color: Colors.white,
padding: const EdgeInsets.all(24),
margin: const EdgeInsets.only(top: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(
S.of(context).phone_number,
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.w700,
color: Colors.white,
),
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 60),
child: Text(
S.of(context).phone_number_product_description,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.white,
Padding(
padding: const EdgeInsets.only(bottom: 60),
child: Text(
S.of(context).phone_number_product_description,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
],
],
),
),
),
],

View file

@ -23,7 +23,7 @@ class CakePhoneVerificationPage extends BasePage {
fontSize: 22,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: titleColor ?? Theme.of(context).primaryTextTheme.title.color),
color: Theme.of(context).primaryTextTheme.title.color),
);
}
}

View file

@ -555,5 +555,14 @@
"get_phone_number": "Get Phone Number",
"choose_phone_products": "Choose from the following available options:",
"phone_number": "Phone Number",
"phone_number_product_description": "SMS messages are forwarded to your email address. Includes 20 free SMS messages for each month of service with the option to pay for more."
"phone_number_product_description": "SMS messages are forwarded to your email address. Includes 20 free SMS messages for each month of service with the option to pay for more.",
"initial_service_term": "Initial Service Term",
"phone_number_promotion_text": "You can add more time later. Save big on longer terms!",
"pay_with_cake_phone": "Pay with CakePhone Balance",
"pay_with_xmr": "Pay with XMR",
"due_today": "Due today:",
"free_sms_email_forward": "Free SMS Email Forwards",
"month": "month",
"then": "then",
"per_message": "per message"
}