diff --git a/assets/fonts/Poppins-Medium.ttf b/assets/fonts/Poppins-Medium.ttf new file mode 100644 index 0000000..6bcdcc2 Binary files /dev/null and b/assets/fonts/Poppins-Medium.ttf differ diff --git a/assets/images/Preview.png b/assets/images/Preview.png new file mode 100644 index 0000000..2d6c185 Binary files /dev/null and b/assets/images/Preview.png differ diff --git a/assets/images/Reviews.png b/assets/images/Reviews.png new file mode 100644 index 0000000..4727764 Binary files /dev/null and b/assets/images/Reviews.png differ diff --git a/assets/images/profileImage.jpg b/assets/images/profileImage.jpg new file mode 100644 index 0000000..7135677 Binary files /dev/null and b/assets/images/profileImage.jpg differ diff --git a/lib/main.dart b/lib/main.dart index bcc58f7..1ee77d1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,6 @@ +import 'package:book_store_app/screens/home_screen.dart'; import 'package:flutter/material.dart'; +import 'package:get/get_navigation/src/root/get_material_app.dart'; void main() { runApp(const MyApp()); @@ -9,12 +11,9 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - body: Center( - child: Text("Book Store App"), - ), - ), + return const GetMaterialApp( + debugShowCheckedModeBanner: false, + home: HomeScreen(), ); } } diff --git a/lib/models/book.dart b/lib/models/book.dart new file mode 100644 index 0000000..9ec0c3f --- /dev/null +++ b/lib/models/book.dart @@ -0,0 +1,202 @@ +import 'package:book_store_app/models/mytext.dart'; +import 'package:book_store_app/models/rate_stars.dart'; +import 'package:book_store_app/screens/book_info.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class Book extends StatelessWidget { + Book({ + Key? key, + required this.myurl, + required this.name, + required this.auther, + required this.prise, + required this.rate, + this.incart = false, + this.likeit = false, + this.desc = '', + }); + + final String myurl; + final String name; + final String auther; + final double prise; + final String desc; + final double rate; + bool incart; + bool likeit; + + static Map libriry = { + 'Dark Psychology Secrets': Book( + name: 'Dark Psychology Secrets', + auther: 'Daniel James Hollins', + rate: 5, + myurl: + 'https://covers.zlibcdn2.com/covers299/books/59/0e/00/590e0059150e05d0d7e142417189a870.jpg', + prise: 40.5, + desc: + 'Whether you have been experiencing manipulation for years, or if this is something entirely new, psychological manipulation can be tricky to decipher. Mostly because the manipulators themselves are true masters of emotional disguise. More often than not, their sweet talking covers their self-serving, dishonest, and, on the whole, sinister intentions. On top of this confusing mismatch of words and examples have also been included in this text to help you get the hang of pinpointing and understanding what emotional manipulation looks like in the real world.', + ), + 'Exactly What to Say': Book( + name: 'Exactly What to Say', + auther: 'Phil M. Jones', + rate: 3.5, + myurl: + 'https://covers.zlibcdn2.com/covers299/books/e1/a0/52/e1a052b5428f021f54ae7d469b261674.jpg', + prise: 15, + desc: + 'Often the decision between a customer choosing you over someone like you is your ability to know exactly what to say, when to say it, and how to make it count. Phil M. Jones has trained more than two million people across five continents and over fifty countries in the lost art of spoken communication. In Exactly What to Say, he delivers the tactics you need to get more of what you want.', + ), + 'The Little Prince': Book( + name: 'The Little Prince', + auther: 'Antoine De Saint-Exupery', + rate: 2.5, + myurl: + 'https://covers.zlibcdn2.com/covers299/books/2c/db/3b/2cdb3b46f0bd12bb4e508b7247777e51.png', + prise: 10.5, + desc: + 'This parable tells the story of an air pilot who meets a Little Prince when he has to make a forced landing in the Sahara Desert. The Little Prince tells him wise and enchanted stories.', + ), + 'The Darkest Temptation': Book( + name: 'The Darkest Temptation', + auther: 'Danielle Lori', + rate: 4, + myurl: + 'https://covers.zlibcdn2.com/covers299/books/68/dc/12/68dc12c16a144773c8cecfeccc5aa30a.jpg', + prise: 25, + desc: + 'This story is dark romance at its best. Simply perfection!"Charmaine Pauls, USA Today bestselling author'), + 'Mechatronics': Book( + name: 'Mechatronics', + auther: 'William Bolton', + rate: 4.5, + myurl: + 'https://covers.zlibcdn2.com/covers299/books/00/6f/b5/006fb52325cf1242508846ff0bb3490e.jpg', + prise: 18.99, + desc: + 'The integration of electronic engineering, mechanical engineering, control and computer engineering - Mechatronics - lies at the heart of the innumerable gadgets, processes and technology without which modern life would seem impossible. From auto-focus cameras to car engine management systems, and from state-of-the-art robots to the humble washing machine, Mechatronics has a hand in them all.This book presents a clear and comprehensive introduction to the area. Practical and applied, it helps you to acquire the mix of skills you will need to comprehend and design mechatronic systems. It also goes much deeper, explaining the very philosophy of mechatronics, and, in so doing, provides you with a frame of understanding to develop a truly interdisciplinary and integrated approach to engineering.'), + }; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(bottom: 20), + child: Row( + children: [ + GestureDetector( + onTap: () { + Get.to(() => BookInfo( + name: name, + auther: auther, + desc: desc, + myurl: myurl, + prise: prise, + rate: rate, + )); + }, + child: Image( + image: NetworkImage(myurl), + height: 106, + width: 72, + fit: BoxFit.cover, + ), + ), + const SizedBox( + width: 20.0, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mytext( + texty: name, + isbold: true, + sizy: 20, + ), + const SizedBox( + height: 10.0, + ), + mytext( + texty: auther, + sizy: 14, + colory: Colors.grey, + ), + const SizedBox( + height: 10.0, + ), + mytext( + texty: '\$$prise', + isbold: true, + ), + const SizedBox( + height: 10.0, + ), + FiveStarRow(rate: rate) + ], + ), + ), + StatefulBuilder(builder: (BuildContext context, mysetState) { + return IconButton( + icon: Icon( + likeit ? Icons.bookmark_added : Icons.bookmark_border, + color: likeit ? Colors.red : Colors.black, + ), + onPressed: () { + mysetState(() => likeit = !likeit); + }, + ); + }) + ], + ), + ); + } +} + +class FiveStarRow extends StatelessWidget { + const FiveStarRow({ + Key? key, + required this.rate, + }) : super(key: key); + + final double rate; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Star( + mynum: 1, + rate: rate, + ), + const SizedBox( + height: 10.0, + ), + Star( + mynum: 2, + rate: rate, + ), + const SizedBox( + height: 10.0, + ), + Star( + mynum: 3, + rate: rate, + ), + const SizedBox( + height: 10.0, + ), + Star( + mynum: 4, + rate: rate, + ), + const SizedBox( + height: 10.0, + ), + Star( + mynum: 5, + rate: rate, + ), + ], + ); + } +} diff --git a/lib/models/mytext.dart b/lib/models/mytext.dart new file mode 100644 index 0000000..1b006a9 --- /dev/null +++ b/lib/models/mytext.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +Widget mytext( + {required String texty, + bool isbold = false, + double sizy = 15, + Color colory = Colors.black}) { + return Text( + texty, + style: TextStyle( + fontWeight: isbold ? FontWeight.bold : FontWeight.normal, + fontSize: sizy, + color: colory), + ); +} diff --git a/lib/models/rate_stars.dart b/lib/models/rate_stars.dart new file mode 100644 index 0000000..c66ea98 --- /dev/null +++ b/lib/models/rate_stars.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +class Star extends StatelessWidget { + Star({ + super.key, + required this.mynum, + required this.rate, + }); + final int mynum; + final double rate; + @override + Widget build(BuildContext context) { + return Icon( + icon(num: mynum, rate: rate), + color: iconColor(num: mynum, rate: rate), + size: 18, + ); + } +} + +IconData icon({required int num, required double rate}) { + if (rate >= num || rate <= num - 1) { + return Icons.star; + } else { + return Icons.star_half_sharp; + } +} + +Color iconColor({required int num, required double rate}) { + if (rate >= num - 0.5) { + return Colors.amber; + } else { + return Colors.grey; + } +} diff --git a/lib/screens/add_books_screen.dart b/lib/screens/add_books_screen.dart new file mode 100644 index 0000000..fa93ce2 --- /dev/null +++ b/lib/screens/add_books_screen.dart @@ -0,0 +1,187 @@ +import 'package:book_store_app/models/book.dart'; +import 'package:book_store_app/models/mytext.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get/get.dart'; + +class AddBooks extends StatelessWidget { + const AddBooks({super.key}); + + @override + Widget build(BuildContext context) { + TextEditingController namec = TextEditingController(); + TextEditingController autherc = TextEditingController(); + TextEditingController pricec = TextEditingController(); + TextEditingController imagec = TextEditingController(); + TextEditingController descc = TextEditingController(); + TextEditingController ratec = TextEditingController(); + return Scaffold( + resizeToAvoidBottomInset: false, + backgroundColor: const Color.fromARGB(255, 243, 243, 243), + //! appbar + appBar: AppBar( + systemOverlayStyle: const SystemUiOverlayStyle( + statusBarBrightness: Brightness.light, + statusBarColor: Colors.transparent), + backgroundColor: const Color.fromARGB(255, 243, 243, 243), + elevation: 0, + leading: DeffultAppbar( + onpress: () { + Get.back(); + }, + ), + leadingWidth: 65, + toolbarHeight: 55, + actions: const [ + Padding( + padding: EdgeInsets.only(right: 20, top: 5), + child: Icon( + Icons.more_vert, + color: Colors.black, + size: 30, + ), + ) + ], + ), + //!body + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Add Book', + style: TextStyle( + fontSize: 27, + fontWeight: FontWeight.bold, + ), + ), + Padding( + padding: const EdgeInsets.only(top: 30, right: 10, left: 10), + child: Column( + children: [ + DeffultTextfield( + hint: 'Book Name', + defultcontroller: namec, + ), + DeffultTextfield( + hint: 'Author Name', + defultcontroller: autherc, + ), + DeffultTextfield( + hint: 'Price', + defultcontroller: pricec, + ), + DeffultTextfield( + hint: 'rate', + defultcontroller: ratec, + ), + DeffultTextfield( + hint: 'Image link', + defultcontroller: imagec, + ), + DeffultTextfield( + hint: 'Description', + defultcontroller: descc, + max: 5, + ), + Container( + height: 50, + width: double.maxFinite, + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular( + 16, + ), + ), + child: TextButton( + onPressed: () { + Book.libriry[namec.text] = Book( + myurl: imagec.text, + name: namec.text, + auther: autherc.text, + desc: descc.text, + prise: double.parse(pricec.text), + rate: double.parse(ratec.text)); + }, + child: mytext( + texty: 'Add', + colory: Colors.white, + sizy: 16, + ), + ), + ) + ], + ), + ) + ], + ), + ), + )); + } +} + +//! ---------------------------------------------------------------- + +class DeffultTextfield extends StatelessWidget { + const DeffultTextfield( + {Key? key, + required this.hint, + this.max = 1, + required this.defultcontroller}) + : super(key: key); + + final String hint; + final int max; + final TextEditingController defultcontroller; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + TextFormField( + controller: defultcontroller, + maxLines: max, + decoration: InputDecoration( + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide.none, + ), + hintText: hint, + hintStyle: const TextStyle( + fontFamily: 'Poppins', fontSize: 16, color: Colors.grey), + fillColor: const Color(0xffFFFFFF), + filled: true, + ), + ), + const SizedBox( + height: 20, + ) + ], + ); + } +} + +//! ---------------------------------------------------------------- + +class DeffultAppbar extends StatelessWidget { + const DeffultAppbar({ + Key? key, + required this.onpress, + }) : super(key: key); + + final Function() onpress; + + @override + Widget build(BuildContext context) { + return IconButton( + icon: const Icon( + Icons.keyboard_arrow_left, + color: Colors.black, + size: 40, + ), + onPressed: onpress, + ); + } +} diff --git a/lib/screens/book_info.dart b/lib/screens/book_info.dart new file mode 100644 index 0000000..2bfe29d --- /dev/null +++ b/lib/screens/book_info.dart @@ -0,0 +1,170 @@ +import 'package:book_store_app/models/book.dart'; +import 'package:book_store_app/models/mytext.dart'; +import 'package:book_store_app/screens/add_books_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get/get_connect/http/src/utils/utils.dart'; +import 'package:get/get_core/src/get_main.dart'; +import 'package:get/get_navigation/get_navigation.dart'; + +class BookInfo extends StatelessWidget { + const BookInfo( + {super.key, + required this.myurl, + required this.name, + required this.auther, + required this.prise, + required this.desc, + required this.rate}); + + final String myurl; + final String name; + final String auther; + final double prise; + final String desc; + final double rate; + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: false, + backgroundColor: const Color.fromARGB(255, 243, 243, 243), + //! appbar + appBar: AppBar( + systemOverlayStyle: const SystemUiOverlayStyle( + statusBarBrightness: Brightness.light, + statusBarColor: Colors.transparent), + backgroundColor: const Color.fromARGB(255, 243, 243, 243), + elevation: 0, + leading: DeffultAppbar( + onpress: () { + Get.back(); + }, + ), + leadingWidth: 65, + toolbarHeight: 55, + actions: const [ + Padding( + padding: EdgeInsets.only(right: 20, top: 5), + child: Icon( + Icons.more_vert, + color: Colors.black, + size: 30, + ), + ) + ], + ), + //!body + body: Container( + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20), + width: double.maxFinite, + child: Column( + children: [ + Image( + image: NetworkImage( + myurl, + ), + height: 225, + ), + const SizedBox( + height: 20, + ), + mytext(texty: name, isbold: T, sizy: 20), + const SizedBox( + height: 10, + ), + mytext(texty: auther, colory: Colors.grey), + const SizedBox( + height: 10, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FiveStarRow(rate: rate), + const SizedBox( + width: 10, + ), + //todo rate + mytext(texty: '$rate / 5.0'), + ], + ), + const SizedBox( + height: 20, + ), + SizedBox( + height: 100, + child: SingleChildScrollView( + child: Text( + desc, + style: const TextStyle(fontSize: 18, height: 1.5), + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Container( + height: 40, + width: 154, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Colors.white), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image(image: AssetImage('assets/images/Preview.png')), + SizedBox( + width: 10, + ), + mytext(texty: 'Preview') + ], + ), + ), + Container( + height: 40, + width: 154, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Colors.white), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image(image: AssetImage('assets/images/Reviews.png')), + SizedBox( + width: 10, + ), + mytext(texty: 'Reviews') + ], + ), + ) + ], + ), + const SizedBox( + height: 20, + ), + Container( + height: 60, + width: double.maxFinite, + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular( + 16, + ), + ), + child: TextButton( + onPressed: () { + Book.libriry[name]!.incart = true; + }, + child: mytext( + texty: 'Buy Now for \$$prise', + colory: Colors.white, + sizy: 16, + ), + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart new file mode 100644 index 0000000..fc70949 --- /dev/null +++ b/lib/screens/home_screen.dart @@ -0,0 +1,274 @@ +import 'package:book_store_app/models/book.dart'; +import 'package:book_store_app/screens/add_books_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get/get.dart'; + +class HomeScreen extends StatelessWidget { + const HomeScreen({super.key}); + + static TextEditingController controller = TextEditingController(); + static RxString controllertext = controller.text.obs; + + @override + Widget build(BuildContext context) { + RxBool liket = false.obs; + RxBool cart = false.obs; + RxBool home = true.obs; + RxString colorText = 'home'.obs; + + return Scaffold( + resizeToAvoidBottomInset: false, + backgroundColor: const Color.fromARGB(255, 243, 243, 243), + //! appbar + appBar: AppBar( + systemOverlayStyle: const SystemUiOverlayStyle( + statusBarBrightness: Brightness.light, + statusBarColor: Colors.transparent), + backgroundColor: const Color.fromARGB(255, 243, 243, 243), + elevation: 0, + leading: const AppBarLeading(), + leadingWidth: 65, + toolbarHeight: 55, + title: const AppBarTitle(), + actions: const [ + Padding( + padding: EdgeInsets.only(right: 20, top: 5), + child: Icon( + Icons.more_vert, + color: Colors.black, + size: 30, + ), + ) + ], + ), + //! body + body: Container( + padding: const EdgeInsets.all(20.0), + height: 800, + //! main column + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + Obx(() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (home.value) const SearchBar(), //! + const SizedBox( + height: 20.0, + ), + Text( + title(cart: cart.value, saved: liket.value), //! + style: const TextStyle( + fontSize: 25, fontWeight: FontWeight.bold), + ), + + const SizedBox( + height: 20.0, + ), + Expanded( + child: SingleChildScrollView( + child: SizedBox( + width: double.maxFinite, + child: Column( + //todo + children: myview( + cart: cart.value, + saved: liket.value, + s: controllertext.value), + ), + ), + ), + ) + ], + ); + }), + //! stack buttons + Padding( + padding: const EdgeInsets.only(bottom: 10), + child: Container( + width: 240, + height: 70, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(22.0), + color: Colors.white, + ), + child: Obx(() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + IconButton( + icon: Icon( + Icons.home_filled, + color: colorText.value == 'home' + ? Colors.black + : Colors.grey, + ), + onPressed: () { + liket.value = false; + cart.value = false; + home.value = true; + colorText.value = 'home'; + }, + ), + IconButton( + icon: Icon( + Icons.bookmark, + color: colorText.value == 'liket' + ? Colors.black + : Colors.grey, + ), + onPressed: () { + liket.value = true; + cart.value = false; + home.value = false; + colorText.value = 'liket'; + }, + ), + IconButton( + icon: Icon( + Icons.shopping_cart_rounded, + color: colorText.value == 'cart' + ? Colors.black + : Colors.grey, + ), + onPressed: () { + liket.value = false; + cart.value = true; + home.value = false; + colorText.value = 'cart'; + }, + ), + IconButton( + icon: const Icon( + Icons.add, + color: Colors.grey, + ), + onPressed: () { + Get.to(const AddBooks()); + }, + ), + ], + ); + }), + ), + ) + ], + ), + ), + ); + } +} + +//!-------------------------------------------------------- + +class SearchBar extends StatelessWidget { + const SearchBar({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return TextFormField( + controller: HomeScreen.controller, + onChanged: (v) { + HomeScreen.controllertext.value = HomeScreen.controller.text; + }, + decoration: InputDecoration( + suffixIcon: const Padding( + padding: EdgeInsets.only(right: 10), + child: Icon( + Icons.search, + size: 30, + color: Colors.grey, + ), + ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide.none, + ), + hintText: 'Search...', + hintStyle: const TextStyle( + fontFamily: 'Poppins', fontSize: 15, color: Colors.grey), + fillColor: const Color(0xffFFFFFF), + filled: true, + ), + ); + } +} + +//!-------------------------------------------------------- + +class AppBarTitle extends StatelessWidget { + const AppBarTitle({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only(top: 5), + height: 60, + alignment: Alignment.centerLeft, + child: const Text( + 'Hi, Mohammed!', + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: 18.0, + fontFamily: 'Poppins', + ), + ), + ); + } +} + +//!-------------------------------------------------------- + +class AppBarLeading extends StatelessWidget { + const AppBarLeading({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + alignment: Alignment.bottomLeft, + padding: const EdgeInsets.only( + left: 20.0, + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: const Image( + image: AssetImage( + 'assets/images/profileImage.jpg', + ), + ), + ), + ); + } +} + +//!--------------------------------- +String title({required bool saved, required bool cart}) { + if (saved) { + return 'Saved'; + } else if (cart) { + return 'Cart'; + } else { + return 'Book List'; + } +} + +//!--------------------------------- +List myview( + {required bool saved, required bool cart, required String s}) { + if (saved) { + return Book.libriry.values.where((e) => e.likeit).toList(); + } else if (cart) { + return Book.libriry.values.where((e) => e.incart).toList(); + } else { + return Book.libriry.values.where((e) => e.name.contains(s)).toList(); + } +} diff --git a/pubspec.lock b/pubspec.lock index 7bc8bdd..62f34da 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -74,6 +74,13 @@ packages: description: flutter source: sdk version: "0.0.0" + get: + dependency: "direct main" + description: + name: get + url: "https://pub.dartlang.org" + source: hosted + version: "4.6.5" lints: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index cd0f457..98f6b79 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,6 +29,7 @@ environment: dependencies: flutter: sdk: flutter + get: ^4.6.5 # The following adds the Cupertino Icons font to your application. @@ -58,8 +59,8 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg + assets: + - assets/images/ # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see @@ -73,10 +74,10 @@ flutter: # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf + fonts: + - family: Poppins + fonts: + - asset: assets/fonts/Poppins-Medium.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro