diff --git a/car_booking/assets/images/av.png b/car_booking/assets/images/av.png new file mode 100644 index 0000000..0011f6a Binary files /dev/null and b/car_booking/assets/images/av.png differ diff --git a/car_booking/assets/images/bentley.png b/car_booking/assets/images/bentley.png new file mode 100644 index 0000000..9922ed7 Binary files /dev/null and b/car_booking/assets/images/bentley.png differ diff --git a/car_booking/assets/images/cadillac.png b/car_booking/assets/images/cadillac.png new file mode 100644 index 0000000..3243c1e Binary files /dev/null and b/car_booking/assets/images/cadillac.png differ diff --git a/car_booking/assets/images/maserati.png b/car_booking/assets/images/maserati.png new file mode 100644 index 0000000..efddbdd Binary files /dev/null and b/car_booking/assets/images/maserati.png differ diff --git a/car_booking/assets/images/rolls_royce.png b/car_booking/assets/images/rolls_royce.png new file mode 100644 index 0000000..92ae3b1 Binary files /dev/null and b/car_booking/assets/images/rolls_royce.png differ diff --git a/car_booking/lib/constants.dart b/car_booking/lib/constants.dart new file mode 100644 index 0000000..9071749 --- /dev/null +++ b/car_booking/lib/constants.dart @@ -0,0 +1,16 @@ + +import 'package:flutter/material.dart'; + +import 'model/car.dart'; + + +Color mPrimaryColor = Color(0xFF40ac9c); + +Color mCardColor = Color(0xFF203e5a); + +List carList = [ + Car('assets/images/bentley.png', 120, 'Bentley', '3A 9200', '77/km', '5,5 L'), + Car('assets/images/rolls_royce.png', 185, 'RR', '3A 9200', '77/km', '5,5 L'), + Car('assets/images/maserati.png', 100, 'Maserati', '3A 9200', '77/km', '5,5 L'), + Car('assets/images/cadillac.png', 90, 'Cadillac', '3A 9200', '77/km', '5,5 L'), +]; diff --git a/car_booking/lib/main.dart b/car_booking/lib/main.dart index bcf1b42..ec7c532 100644 --- a/car_booking/lib/main.dart +++ b/car_booking/lib/main.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'screens/available/available_car_screen.dart'; +import 'screens/detail/car_detail_screen.dart'; import 'screens/login/login_screen.dart'; import 'screens/signup/singup_screen.dart'; @@ -28,7 +30,7 @@ class MyApp extends StatelessWidget { routes: { '/': (context) => LoginScreen(), 'CreateNewAccount': (context) => CreateNewAccount(), - + 'AvailableCarScreen': (context) => AvailableCarScreen(), }, ); } diff --git a/car_booking/lib/model/car.dart b/car_booking/lib/model/car.dart new file mode 100644 index 0000000..73972eb --- /dev/null +++ b/car_booking/lib/model/car.dart @@ -0,0 +1,17 @@ +class Car { + String image; + int price; + String brand; + String model; + String co2; + String fuelCons; + + Car( + this.image, + this.price, + this.brand, + this.model, + this.co2, + this.fuelCons, + ); +} diff --git a/car_booking/lib/screens/available/available_car_screen.dart b/car_booking/lib/screens/available/available_car_screen.dart new file mode 100644 index 0000000..9a1e90a --- /dev/null +++ b/car_booking/lib/screens/available/available_car_screen.dart @@ -0,0 +1,49 @@ + +import 'package:car_booking/screens/login/login_screen.dart'; +import 'package:flutter/material.dart'; + +import '../../constants.dart'; +import 'widget/car_list_item.dart'; + +class AvailableCarScreen extends StatelessWidget { + + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: mPrimaryColor, + appBar: buildAppBar(), + body: ListView.builder( + itemCount: carList.length, + itemBuilder: (context, index) => CarListItem(index), + ), + ); + } + + AppBar buildAppBar() { + return AppBar( + backgroundColor: mPrimaryColor, + elevation: 0, + leading: IconButton( + icon: Icon( + Icons.menu, + color: Colors.white, + ), + onPressed: () {}, + ) , + title: Text('Dzenix Available Cars'), + actions: [ + IconButton( + icon: Icon( + Icons.logout, + color: Colors.white, + ), + onPressed: () { + + }, + ) + ], + ); + } +} + diff --git a/car_booking/lib/screens/available/widget/car_infomation.dart b/car_booking/lib/screens/available/widget/car_infomation.dart new file mode 100644 index 0000000..5185b7b --- /dev/null +++ b/car_booking/lib/screens/available/widget/car_infomation.dart @@ -0,0 +1,72 @@ + +import 'package:flutter/material.dart'; + +import '../../../constants.dart'; +import '../../../model/car.dart'; +import '../../../widget/attribute.dart'; + +class CarInfomation extends StatelessWidget { + const CarInfomation({ + + required this.car, + }) ; + + final Car car; + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + margin: EdgeInsets.only(left: 24, right: 24,top: 50), + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: mCardColor, + borderRadius: BorderRadius.circular(16), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '\$${car.price}', + style: TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + Text( + 'price/hr', + style: TextStyle( + color: Colors.white, + ), + ), + SizedBox( + height: 16, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Attribute( + value: car.brand, + name: 'Brand', + ), + Attribute( + value: car.model, + name: 'Model No', + ), + Attribute( + value: car.co2, + name: 'CO2', + ), + Attribute( + value: car.fuelCons, + name: 'Fule Cons.', + ), + ], + ) + ], + ), + ); + } +} + diff --git a/car_booking/lib/screens/available/widget/car_list_item.dart b/car_booking/lib/screens/available/widget/car_list_item.dart new file mode 100644 index 0000000..2bae343 --- /dev/null +++ b/car_booking/lib/screens/available/widget/car_list_item.dart @@ -0,0 +1,48 @@ + +import 'package:flutter/material.dart'; + +import '../../../constants.dart'; +import '../../../model/car.dart'; + +import 'car_infomation.dart'; + +class CarListItem extends StatelessWidget { + const CarListItem( + this.index, + + ) ; + + final int index; + + @override + Widget build(BuildContext context) { + Car car = carList[index]; + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return CarDetailScreen(); + }, + ), + ); + }, + child: Container( + margin: EdgeInsets.only(bottom: 20), + child: Stack( + children: [ + CarInfomation(car: car), + Positioned( + right: 40, + child: Image.asset( + car.image, + height: 100, + ), + ) + ], + ), + ), + ); + } +} diff --git a/car_booking/lib/widget/attribute.dart b/car_booking/lib/widget/attribute.dart new file mode 100644 index 0000000..643572a --- /dev/null +++ b/car_booking/lib/widget/attribute.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +class Attribute extends StatelessWidget { + const Attribute({ + + required this.name, + required this.value, + this.textColor = Colors.white, + }); + + final String name, value; + final Color textColor; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + value, + style: TextStyle( + color: textColor, + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + Text( + name, + style: TextStyle( + color: textColor, + fontSize: 12, + ), + ) + ], + ); + } +} diff --git a/car_booking/lib/widget/rating_bar.dart b/car_booking/lib/widget/rating_bar.dart new file mode 100644 index 0000000..7b56afd --- /dev/null +++ b/car_booking/lib/widget/rating_bar.dart @@ -0,0 +1,174 @@ +import 'package:flutter/material.dart'; + +class RatingBar extends StatefulWidget { + final int count; + final double maxRating; + final double value; + final double size; + final double padding; + final bool selectAble; + final Color selectColor; + final ValueChanged onRatingUpdate; + + RatingBar( + {this.maxRating = 10.0, + this.count = 5, + this.value = 10.0, + this.size = 20, + required this.padding, + this.selectColor = Colors.blue, + this.selectAble = false, + required this.onRatingUpdate}); + + @override + _RatingBarState createState() => _RatingBarState(); +} + +class _RatingBarState extends State { + late double value; + + @override + Widget build(BuildContext context) { + value = widget.value; + return Listener( + child: buildRowRating(), + onPointerDown: (PointerDownEvent event) { + double x = event.localPosition.dx; + if (x < 0) x = 0; + pointValue(x); + }, + onPointerMove: (PointerMoveEvent event) { + double x = event.localPosition.dx; + if (x < 0) x = 0; + pointValue(x); + }, + onPointerUp: (_) {}, + behavior: HitTestBehavior.deferToChild, + ); + } + + pointValue(double dx) { + if (!widget.selectAble) { + return; + } + if (dx >= + widget.size * widget.count + widget.padding * (widget.count - 1)) { + value = widget.maxRating; + } else { + for (double i = 1; i < widget.count + 1; i++) { + if (dx > widget.size * i + widget.padding * (i - 1) && + dx < widget.size * i + widget.padding * i) { + value = i * (widget.maxRating / widget.count); + break; + } else if (dx > widget.size * (i - 1) + widget.padding * (i - 1) && + dx < widget.size * i + widget.padding * i) { + value = (dx - widget.padding * (i - 1)) / + (widget.size * widget.count) * + widget.maxRating; + break; + } + } + } + setState(() { + widget.onRatingUpdate(value.toStringAsFixed(1)); + }); + } + + Widget buildRowRating() { + return Container( + child: Stack( + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: buildNormalRow(), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: buildRow(), + ) + ], + ), + ); + } + + List buildRow() { + int full = fullStars(); + List children = []; + for (int i = 0; i < full; i++) { + children.add(Icon( + Icons.star, + color: widget.selectColor, + size: widget.size, + )); + if (i < widget.count - 1) { + children.add( + SizedBox( + width: widget.padding, + ), + ); + } + } + if (full < widget.count) { + children.add(ClipRect( + clipper: SMClipper(rating: star() * widget.size), + child: Icon( + Icons.star, + color: widget.selectColor, + size: widget.size, + ), + )); + } + return children; + } + + List buildNormalRow() { + List children = []; + for (int i = 0; i < widget.count; i++) { + children.add(Icon( + Icons.star, + color: Colors.grey, + size: widget.size, + )); + if (i < widget.count - 1) { + children.add(SizedBox( + width: widget.padding, + )); + } + } + return children; + } + + int fullStars() { + if (value != null) { + return (value / (widget.maxRating / widget.count)).floor(); + } + return 0; + } + + double star() { + if (value != null) { + if (widget.count / fullStars() == widget.maxRating / value) { + return 0; + } + return (value % (widget.maxRating / widget.count)) / + (widget.maxRating / widget.count); + } + return 0; + } +} + +class SMClipper extends CustomClipper { + final double rating; + + SMClipper({required this.rating}) : assert(rating != null); + + @override + Rect getClip(Size size) { + return Rect.fromLTRB(0.0, 0.0, rating, size.height); + } + + @override + bool shouldReclip(SMClipper oldClipper) { + return rating != oldClipper.rating; + } +}