diff --git a/assets/explore/drawing_board.svg b/assets/explore/drawing_board.svg new file mode 100644 index 0000000..d0a52e9 --- /dev/null +++ b/assets/explore/drawing_board.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/landing_page.dart b/lib/landing_page.dart index 2ce3fec..75efec7 100644 --- a/lib/landing_page.dart +++ b/lib/landing_page.dart @@ -90,7 +90,7 @@ class _LandingPageState extends State { onPressed: () { Navigator.popAndPushNamed( context, - AllRoutesConstant.mainhome, + AllRoutesConstant.mainhomeRoute, ); }, child: Text( diff --git a/lib/main.dart b/lib/main.dart index f3b3b3c..d7f3bd0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -26,4 +26,4 @@ class MyApp extends StatelessWidget { onGenerateRoute: Routers.generateRoute, ); } -} +} \ No newline at end of file diff --git a/lib/pages/explore.dart b/lib/pages/explore.dart index 42cdf60..2fb78ea 100644 --- a/lib/pages/explore.dart +++ b/lib/pages/explore.dart @@ -1,6 +1,8 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:learn/utils/constants.dart'; +import 'package:learn/utils/route/route_constant.dart'; import '../utils/const_dimensions.dart'; @@ -12,141 +14,182 @@ class ExplorePage extends StatelessWidget { Widget build(BuildContext context) { return SafeArea( child: CustomScrollView( - slivers: [ - SliverAppBar( - title: Padding( - padding: const EdgeInsets.fromLTRB(0, 12, 16, 4), - child: Text( - "Explore", - style: Theme.of(context) - .textTheme - .headlineLarge! - .copyWith(fontWeight: FontWeight.bold, fontSize: 30.0), - ), - ), - ), - SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - return GestureDetector( - onTap: () => Navigator.push( - context, - AppConstants.modules[index].route, + slivers: [ + SliverAppBar( + title: Padding( + padding: const EdgeInsets.fromLTRB(0, 12, 16, 4), + child: Text( + "Explore", + style: Theme.of(context) + .textTheme + .headlineLarge! + .copyWith(fontWeight: FontWeight.bold, fontSize: 30.0), ), - child: Container( - margin: const EdgeInsets.symmetric( - horizontal: 24, vertical: 12), - height: ConstantDimensions.heightExtraLarge * 4, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - spreadRadius: 2, - blurRadius: 5, - offset: const Offset(0, 3), - ), - ], + ), + ), + SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + return GestureDetector( + onTap: () => Navigator.push( + context, + AppConstants.modules[index].route, ), - child: ClipRRect( - borderRadius: BorderRadius.circular(16), - child: Stack( - fit: StackFit.expand, - alignment: Alignment.center, - children: [ - ImageFiltered( - imageFilter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), - child: Image.asset( - AppConstants.modules[index].thumbnailPath, - fit: BoxFit.cover, + child: Container( + margin: const EdgeInsets.symmetric( + horizontal: 24, vertical: 12), + height: ConstantDimensions.heightExtraLarge * 4, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + spreadRadius: 2, + blurRadius: 5, + offset: const Offset(0, 3), ), - ), - Positioned.fill( - child: Align( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - AppConstants.modules[index].name, - style: Theme.of(context) - .textTheme - .headlineMedium! - .copyWith( - color: Colors.white, - fontWeight: FontWeight.bold, - shadows: [ - const Shadow( - color: Colors.black, - offset: Offset(2, 1), - blurRadius: 4, + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Stack( + fit: StackFit.expand, + alignment: Alignment.center, + children: [ + ImageFiltered( + imageFilter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: Image.asset( + AppConstants.modules[index].thumbnailPath, + fit: BoxFit.cover, + ), + ), + Positioned.fill( + child: Align( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + AppConstants.modules[index].name, + style: Theme.of(context) + .textTheme + .headlineMedium! + .copyWith( + color: Colors.white, + fontWeight: FontWeight.bold, + shadows: [ + const Shadow( + color: Colors.black, + offset: Offset(2, 1), + blurRadius: 4, + ), + ], ), - ], - ), - ), - Text( - AppConstants.modules[index].description, - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: Colors.white, - fontWeight: FontWeight.bold, - shadows: [ - const Shadow( - color: Colors.black, - offset: Offset(2, 1), - blurRadius: 2, + ), + Text( + AppConstants.modules[index].description, + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: Colors.white, + fontWeight: FontWeight.bold, + shadows: [ + const Shadow( + color: Colors.black, + offset: Offset(2, 1), + blurRadius: 2, + ), + ], ), - ], - ), + ), + ], ), - ], + ), ), - ), + ], ), - ], + ), + ), + ); + }, + childCount: AppConstants.modules.length, + ), + ), + + GestureDetector( + onTap: () { + Navigator.pushNamed( + context, + AllRoutesConstant.drawingboardRoute, + ); + }, + child: Container( + margin: const EdgeInsets.all(5.0), + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + border: Border.all(color: Colors.black, width: 1.0), + borderRadius: BorderRadius.circular(8.0), + color: Colors.greenAccent, + ), + child: Row( + children: [ + SizedBox( + width: 50, + height: 50, + child: SvgPicture.asset( + 'assets/explore/drawing_board.svg', + ), + ), + const SizedBox(width: 28.0), + const Text( + 'Drawing Board', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 30.0, + fontFamily: 'Comic', + color: Colors.white, ), - )), - ); - }, - childCount: AppConstants.modules.length, - ), + ), + ], + ), + ), + ), + ], ), - - // GestureDetector( - // onTap: () { - // Navigator.pushNamed(context, '/quiz'); - // }, - // child: Container( - // margin: const EdgeInsets.all(5.0), - // padding: const EdgeInsets.all(8.0), - // decoration: BoxDecoration( - // border: Border.all(color: Colors.black, width: 1.0), - // borderRadius: BorderRadius.circular(8.0), - // color: Colors.blueAccent, - // ), - // child: Row( - // children: [ - // SizedBox( - // width: 50, - // height: 50, - // child: SvgPicture.asset('assets/explore/notebook.svg'), - // ), - // const SizedBox(width: 28.0), - // const Text( - // 'Quiz', - // style: TextStyle( - // fontWeight: FontWeight.bold, - // fontSize: 30.0, - // fontFamily: 'Comic', - // color: Colors.white, - // ), - // ), - // ], - // ), - // ), - // ), - ], - )); + ); } } + + // GestureDetector( + // onTap: () { + // Navigator.pushNamed(context, '/quiz'); + // }, + // child: Container( + // margin: const EdgeInsets.all(5.0), + // padding: const EdgeInsets.all(8.0), + // decoration: BoxDecoration( + // border: Border.all(color: Colors.black, width: 1.0), + // borderRadius: BorderRadius.circular(8.0), + // color: Colors.blueAccent, + // ), + // child: Row( + // children: [ + // SizedBox( + // width: 50, + // height: 50, + // child: SvgPicture.asset('assets/explore/notebook.svg'), + // ), + // const SizedBox(width: 28.0), + // const Text( + // 'Quiz', + // style: TextStyle( + // fontWeight: FontWeight.bold, + // fontSize: 30.0, + // fontFamily: 'Comic', + // color: Colors.white, + // ), + // ), + // ], + // ), + // ), + // ), diff --git a/lib/pages/explore/drawingboard.dart b/lib/pages/explore/drawingboard.dart new file mode 100644 index 0000000..b3c33de --- /dev/null +++ b/lib/pages/explore/drawingboard.dart @@ -0,0 +1,214 @@ +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +class DrawingBoardPage extends StatelessWidget { + const DrawingBoardPage({Key? key}); + + @override + Widget build(BuildContext context) { + return DrawingBoard(); + } +} + +class DrawingBoard extends StatefulWidget { + const DrawingBoard({Key? key}) : super(key: key); + + @override + _DrawingBoardState createState() => _DrawingBoardState(); +} + +class _DrawingBoardState extends State { + Color selectedColor = Colors.black; + double strokeWidth = 5; + bool isEraser = false; + List drawingPoints = []; + List colors = [ + Colors.pink, + Colors.red, + Colors.blue, + Colors.orange, + Colors.yellow, + Colors.purple, + Colors.green, + Colors.black, + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Drawing Board"), + actions: [ + TextButton.icon( + onPressed: () => setState(() => drawingPoints = []), + icon: Icon(Icons.clear), + label: Text("Clear Board"), + style: TextButton.styleFrom( + backgroundColor: Color(0xfff7f2fa), + ), + ), + SizedBox( + width: 10, + ), + ], + ), + + body: Stack( + children: [ + GestureDetector( + onPanStart: (details) { + setState(() { + drawingPoints.add( + DrawingPoint( + details.localPosition, + Paint() + ..color = isEraser? Color(0xfffef7ff) : selectedColor + ..isAntiAlias = true + ..strokeWidth = strokeWidth + ..strokeCap = StrokeCap.round, + ), + ); + }); + }, + + onPanUpdate: (details) { + setState(() { + drawingPoints.add( + DrawingPoint( + details.localPosition, + Paint() + ..color = isEraser? Color(0xfffef7ff) : selectedColor + ..isAntiAlias = true + ..strokeWidth = strokeWidth + ..strokeCap = StrokeCap.round, + ), + ); + }); + }, + + onPanEnd: (details) { + setState(() { + drawingPoints.add(null); + }); + }, + + child: CustomPaint( + painter: _DrawingPainter(drawingPoints), + child: Container( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + ), + ), + ), + + Positioned( + top: 20, + right: 10, + left: 10, + child: Row( + children: [ + Slider( + min: 0, + max: 40, + value: strokeWidth, + onChanged: (val) => setState(() => strokeWidth = val), + ), + SizedBox( + width: 50 + ), + ElevatedButton.icon( + onPressed: () { + setState(() { + isEraser =!isEraser; + if (isEraser) { + selectedColor = Color(0xfffef7ff); + } + }); + }, + icon: Icon(FontAwesomeIcons.eraser), + label: Text("Eraser"), + ), + ], + ), + ), + ], + ), + + bottomNavigationBar: BottomAppBar( + child: Container( + color: Colors.grey[200], + padding: EdgeInsets.all(10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: List.generate( + colors.length, + (index) => _buildColorChoser(colors[index]), + ), + ), + ), + ), + ); + } + + GestureDetector _buildColorChoser(Color color) { + bool isSelected = selectedColor == color; + return GestureDetector( + onTap: () { + setState(() { + selectedColor = color; + isEraser = false; + }); + }, + child: Container( + height: isSelected ? 47 : 40, + width: isSelected ? 47 : 40, + decoration: BoxDecoration( + color: color, + shape: BoxShape.circle, + border: isSelected + ? Border.all( + color: Colors.white, + width: 3, + ) + : null, + ), + ), + ); + } +} + +class _DrawingPainter extends CustomPainter { + final List drawingPoints; + + _DrawingPainter(this.drawingPoints); + + @override + void paint(Canvas canvas, Size size) { + for (int i = 0; i < drawingPoints.length - 1; i++) { + if (drawingPoints[i] != null && drawingPoints[i + 1] != null) { + canvas.drawLine( + drawingPoints[i]!.offset, + drawingPoints[i + 1]!.offset, + drawingPoints[i]!.paint, + ); + } else if (drawingPoints[i] != null && drawingPoints[i + 1] == null) { + canvas.drawPoints( + PointMode.points, + [drawingPoints[i]!.offset], + drawingPoints[i]!.paint, + ); + } + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => true; +} + +class DrawingPoint { + Offset offset; + Paint paint; + + DrawingPoint(this.offset, this.paint); +} diff --git a/lib/pages/explore/explore.dart b/lib/pages/explore/explore.dart index f8b868b..a2fbfdc 100644 --- a/lib/pages/explore/explore.dart +++ b/lib/pages/explore/explore.dart @@ -3,6 +3,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:learn/utils/constants.dart'; +import 'package:learn/utils/route/route_constant.dart'; import '../../utils/const_dimensions.dart'; @@ -48,7 +49,7 @@ class ExplorePage extends StatelessWidget { width: ConstantDimensions.widthExtraLarge, height: ConstantDimensions.heightExtraLarge, child: - SvgPicture.asset('assets/explore/notebook.svg'), + SvgPicture.asset('assets/explore/notebook.svg'), ), const SizedBox(width: ConstantDimensions.widthMedium_Large), const Text( @@ -64,12 +65,45 @@ class ExplorePage extends StatelessWidget { ), ), ), + GestureDetector( + onTap: () { + Navigator.pushNamed(context, AllRoutesConstant.drawingboardRoute); + }, + child: Container( + margin: const EdgeInsets.all(5.0), + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + border: Border.all(color: Colors.black, width: 1.0), + borderRadius: BorderRadius.circular(8.0), + color: Colors.greenAccent, + ), + child: Row( + children: [ + SizedBox( + width: ConstantDimensions.widthExtraLarge, + height: ConstantDimensions.heightExtraLarge, + child: SvgPicture.asset('assets/explore/drawing_board.svg'), + ), + const SizedBox(width: ConstantDimensions.widthMedium_Large), + const Text( + 'Drawing Board', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 30.0, + fontFamily: 'Comic', + color: Colors.white, + ), + ), + ], + ), + ), + ), ], ), ), SliverList( delegate: SliverChildBuilderDelegate( - (context, index) { + (context, index) { return GestureDetector( onTap: () => Navigator.push( context, @@ -98,7 +132,7 @@ class ExplorePage extends StatelessWidget { children: [ ImageFiltered( imageFilter: - ImageFilter.blur(sigmaX: 5, sigmaY: 5), + ImageFilter.blur(sigmaX: 5, sigmaY: 5), child: Image.asset( AppConstants.modules[index].thumbnailPath, fit: BoxFit.cover, @@ -159,4 +193,4 @@ class ExplorePage extends StatelessWidget { ), ); } -} +} \ No newline at end of file diff --git a/lib/utils/route/route_constant.dart b/lib/utils/route/route_constant.dart index c1700ec..788a35d 100644 --- a/lib/utils/route/route_constant.dart +++ b/lib/utils/route/route_constant.dart @@ -16,6 +16,7 @@ class AllRoutesConstant { static const String seasonRoute = "/seasons"; static const String occupationRoute = '/occupations'; static const String fruitRoute = "/fruit"; - static const String landing = '/landing_page'; - static const String mainhome = '/mainhome'; + static const String drawingboardRoute = "/drawingboard"; + static const String landingRoute = '/landing_page'; + static const String mainhomeRoute = '/mainhome'; } diff --git a/lib/utils/route/routes.dart b/lib/utils/route/routes.dart index e6c8de0..4fb1872 100644 --- a/lib/utils/route/routes.dart +++ b/lib/utils/route/routes.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:learn/landing_page.dart'; import 'package:learn/pages/about.dart'; import 'package:learn/pages/explore.dart'; +import 'package:learn/pages/explore/drawingboard.dart'; import 'package:learn/pages/explore/quiz.dart'; import 'package:learn/pages/favorite.dart'; import 'package:learn/pages/fruits.dart'; @@ -55,9 +56,11 @@ class Routers { return slidePageRoute(OccupationPage()); case AllRoutesConstant.fruitRoute: return slidePageRoute(FruitsPage()); - case AllRoutesConstant.landing: + case AllRoutesConstant.drawingboardRoute: + return slidePageRoute(const DrawingBoardPage()); + case AllRoutesConstant.landingRoute: return slidePageRoute(const LandingPage()); - case AllRoutesConstant.mainhome: + case AllRoutesConstant.mainhomeRoute: return slidePageRoute(MainHome()); default: return MaterialPageRoute( @@ -69,4 +72,4 @@ class Routers { ); } } -} +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index b5f6453..d679592 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,7 @@ dependencies: google_nav_bar: ^5.0.6 flutter_bloc: ^8.1.5 animated_text_kit: ^4.2.2 + font_awesome_flutter: ^10.1.0 dev_dependencies: flutter_test: