mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-10 21:04:53 +00:00
Add initial UI for phone number product page
This commit is contained in:
parent
2ed6700b48
commit
57f8ada2b0
8 changed files with 282 additions and 39 deletions
21
lib/entities/service_plan.dart
Normal file
21
lib/entities/service_plan.dart
Normal 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;
|
||||
}
|
|
@ -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(
|
||||
|
|
|
@ -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';
|
||||
}
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue