mirror of
https://github.com/TheAlphamerc/flutter_ecommerce_app.git
synced 2026-03-13 09:30:53 +08:00
added product detail page
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_ecommerce_app/src/config/route.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'src/pages/home_page.dart';
|
||||
import 'src/themes/theme.dart';
|
||||
@@ -16,7 +17,7 @@ class MyApp extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
debugShowCheckedModeBanner: false ,
|
||||
home: MyHomePage(title: 'Flutter Demo Home Page'),
|
||||
routes: Routes.getRoute(),
|
||||
);
|
||||
}
|
||||
}
|
||||
12
lib/src/config/route.dart
Normal file
12
lib/src/config/route.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_ecommerce_app/src/pages/home_page.dart';
|
||||
import 'package:flutter_ecommerce_app/src/pages/product_detail.dart';
|
||||
|
||||
class Routes{
|
||||
static Map<String,WidgetBuilder> getRoute(){
|
||||
return <String, WidgetBuilder>{
|
||||
'/': (_) => MyHomePage(),
|
||||
'/detail': (_) => ProductDetailPage()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,16 @@ class AppData {
|
||||
];
|
||||
static List<Category> categoryList = [
|
||||
Category(),
|
||||
Category(
|
||||
name: "Sneakers",
|
||||
image: 'assets/shoe_thumb_tilt.png',
|
||||
isSelected: true),
|
||||
Category(id:1,name: "Watch", image: 'assets/watch.png'),
|
||||
Category(id:1,name: "Sneakers",image: 'assets/shoe_thumb_2.png',isSelected: true),
|
||||
Category(id:2,name: "Jacket", image: 'assets/jacket.png'),
|
||||
Category(id:3,name: "Watch", image: 'assets/watch.png'),
|
||||
Category(id:4,name: "Watch", image: 'assets/watch.png'),
|
||||
];
|
||||
static List<String> showThumbnailList = [
|
||||
"assets/shoe_thumb_5.png",
|
||||
"assets/shoe_thumb_1.png",
|
||||
"assets/shoe_thumb_4.png",
|
||||
"assets/shoe_thumb_3.png",
|
||||
];
|
||||
static String description = "Clean lines, versatile and timeless—the people shoe returns with the Nike Air Max 90. Featuring the same iconic Waffle sole, stitched overlays and classic TPU accents you come to love, it lets you walk among the pantheon of Air. ßNothing as fly, nothing as comfortable, nothing as proven. The Nike Air Max 90 stays true to its OG running roots with the iconic Waffle sole, stitched overlays and classic TPU details. Classic colours celebrate your fresh look while Max Air cushioning adds comfort to the journey.";
|
||||
}
|
||||
|
||||
347
lib/src/pages/product_detail.dart
Normal file
347
lib/src/pages/product_detail.dart
Normal file
@@ -0,0 +1,347 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_ecommerce_app/src/model/category.dart';
|
||||
import 'package:flutter_ecommerce_app/src/model/data.dart';
|
||||
import 'package:flutter_ecommerce_app/src/themes/light_color.dart';
|
||||
import 'package:flutter_ecommerce_app/src/themes/theme.dart';
|
||||
import 'package:flutter_ecommerce_app/src/wigets/prduct_icon.dart';
|
||||
import 'package:flutter_ecommerce_app/src/wigets/title_text.dart';
|
||||
|
||||
class ProductDetailPage extends StatefulWidget {
|
||||
ProductDetailPage({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ProductDetailPageState createState() => _ProductDetailPageState();
|
||||
}
|
||||
|
||||
class _ProductDetailPageState extends State<ProductDetailPage> {
|
||||
Widget _appBar() {
|
||||
return Container(
|
||||
padding: AppTheme.padding,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: _icon(Icons.arrow_back_ios,
|
||||
color: Colors.black54, size: 15, padding: 12, isOutLine: true),
|
||||
),
|
||||
_icon(Icons.favorite,
|
||||
color: LightColor.red, size: 15, padding: 12, isOutLine: false),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _icon(IconData icon,
|
||||
{Color color = LightColor.iconColor,
|
||||
double size = 20,
|
||||
double padding = 10,
|
||||
bool isOutLine = false}) {
|
||||
return Container(
|
||||
height: 40,
|
||||
width: 40,
|
||||
padding: EdgeInsets.all(padding),
|
||||
margin: EdgeInsets.all(padding),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: LightColor.iconColor,
|
||||
style: isOutLine ? BorderStyle.solid : BorderStyle.none),
|
||||
borderRadius: BorderRadius.all(Radius.circular(13)),
|
||||
color: isOutLine ? Colors.transparent : Theme.of(context).backgroundColor,
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Color(0xfff8f8f8),
|
||||
blurRadius: 5,
|
||||
spreadRadius: 10,
|
||||
offset: Offset(5,5)
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Icon(icon, color: color, size: size),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _productImage() {
|
||||
return Stack(
|
||||
alignment: Alignment.bottomCenter,
|
||||
children: <Widget>[
|
||||
TitleText(
|
||||
text: "AIP",
|
||||
fontSize: 160,
|
||||
color: LightColor.lightGrey,
|
||||
),
|
||||
Image.asset('assets/show_1.png')
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _categoryWidget() {
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 0),
|
||||
width: AppTheme.fullWidth(context),
|
||||
height: 80,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children:
|
||||
AppData.showThumbnailList.map((x) => _thumbnail(x)).toList()),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _thumbnail(String image) {
|
||||
return Container(
|
||||
height: 40,
|
||||
width: 50,
|
||||
margin: EdgeInsets.symmetric(horizontal: 10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: LightColor.grey,
|
||||
),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(13),
|
||||
),
|
||||
// color: Theme.of(context).backgroundColor,
|
||||
),
|
||||
child: Image.asset(image),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _detailWidget() {
|
||||
return DraggableScrollableSheet(
|
||||
maxChildSize: .8,
|
||||
initialChildSize: .53,
|
||||
minChildSize: .53,
|
||||
builder: (context, scrollController) {
|
||||
return Container(
|
||||
padding: AppTheme.padding,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(40),
|
||||
topRight: Radius.circular(40),
|
||||
),
|
||||
color: Colors.white),
|
||||
child: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
SizedBox(height: 5),
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 5,
|
||||
decoration: BoxDecoration(
|
||||
color: LightColor.iconColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(10))),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Container(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
TitleText(text: "NIKE AIR MAX 200", fontSize: 25),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
TitleText(
|
||||
text: "\$ ",
|
||||
fontSize: 18,
|
||||
color: LightColor.red,
|
||||
),
|
||||
TitleText(
|
||||
text: "240",
|
||||
fontSize: 25,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Icon(Icons.star,
|
||||
color: LightColor.yellowColor, size: 17),
|
||||
Icon(Icons.star,
|
||||
color: LightColor.yellowColor, size: 17),
|
||||
Icon(Icons.star,
|
||||
color: LightColor.yellowColor, size: 17),
|
||||
Icon(Icons.star,
|
||||
color: LightColor.yellowColor, size: 17),
|
||||
Icon(Icons.star_border, size: 17),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
_availableSize(),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
_availableColor(),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
_description(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _availableSize() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
TitleText(
|
||||
text: "Available Size",
|
||||
fontSize: 14,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
_sizeWidget("US 6"),
|
||||
_sizeWidget("US 7", isSelected: true),
|
||||
_sizeWidget("US 8"),
|
||||
_sizeWidget("US 9"),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _sizeWidget(String text,
|
||||
{Color color = LightColor.iconColor, bool isSelected = false}) {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: LightColor.iconColor,
|
||||
style: !isSelected ? BorderStyle.solid : BorderStyle.none),
|
||||
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||
color:
|
||||
isSelected ? LightColor.orange : Theme.of(context).backgroundColor,
|
||||
),
|
||||
child: TitleText(
|
||||
text: text,
|
||||
fontSize: 16,
|
||||
color: isSelected ? LightColor.background : LightColor.titleTextColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _availableColor() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
TitleText(
|
||||
text: "Available Size",
|
||||
fontSize: 14,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
_colorWidget(LightColor.yellowColor, isSelected: true),
|
||||
SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
_colorWidget(LightColor.lightBlue),
|
||||
SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
_colorWidget(LightColor.black),
|
||||
SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
_colorWidget(LightColor.red),
|
||||
SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
_colorWidget(LightColor.skyBlue),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _colorWidget(Color color, {bool isSelected = false}) {
|
||||
return CircleAvatar(
|
||||
radius: 12,
|
||||
backgroundColor: color.withAlpha(150),
|
||||
child: isSelected
|
||||
? Icon(
|
||||
Icons.check_circle,
|
||||
color: color,
|
||||
size: 18,
|
||||
)
|
||||
: CircleAvatar(radius: 7, backgroundColor: color),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _description() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
TitleText(
|
||||
text: "Available Size",
|
||||
fontSize: 14,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Text(AppData.description),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
FloatingActionButton _flotingButton(){
|
||||
return FloatingActionButton(
|
||||
onPressed: (){},
|
||||
backgroundColor: LightColor.orange,
|
||||
child: Icon(Icons.shopping_basket, color:Theme.of(context).floatingActionButtonTheme.backgroundColor),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
floatingActionButton: _flotingButton(),
|
||||
body: SafeArea(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Color(0xfffbfbfb),
|
||||
Color(0xfff7f7f7),
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
)),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
_appBar(),
|
||||
_productImage(),
|
||||
_categoryWidget(),
|
||||
],
|
||||
),
|
||||
_detailWidget()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ class LightColor {
|
||||
static const Color darkgrey = Color(0xff747F8F);
|
||||
|
||||
static const Color iconColor = Color(0xffa8a09b);
|
||||
static const Color yellowColor = Color(0xfffbba01);
|
||||
|
||||
static const Color black = Color(0xff20262C);
|
||||
static const Color lightblack = Color(0xff5F5F60);
|
||||
|
||||
@@ -35,11 +35,10 @@ class ProducIcon extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
|
||||
children: <Widget>[
|
||||
model.image != null ? Image.asset(model.image) : SizedBox(),
|
||||
Container(
|
||||
|
||||
model.name == null ? Container()
|
||||
: Container(
|
||||
child: TitleText(
|
||||
text: model.name,
|
||||
fontWeight: FontWeight.w700,
|
||||
|
||||
@@ -25,6 +25,7 @@ class _ProductCardState extends State<ProductCard> {
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed('/detail');
|
||||
setState(() {
|
||||
// model.isSelected = !model.isSelected;
|
||||
// AppData.productList.forEach((x) {
|
||||
|
||||
Reference in New Issue
Block a user