diff --git a/lib/app.dart b/lib/app.dart new file mode 100644 index 0000000..a45572c --- /dev/null +++ b/lib/app.dart @@ -0,0 +1,68 @@ +import 'package:bamboo/foundation/breakpoint.dart'; + +import 'package:flutter/material.dart'; +import 'package:theme_provider/theme_provider.dart'; + +import 'core/theme/app_theme.dart'; +import 'pages/home/home.dart'; + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + ApplicationTheme appTheme = ApplicationTheme(context); + return BambooBreakPoint( + mobile: 576, + tablet: 768, + desktop: 1024, + child: ThemeProvider( + themes: [ + AppTheme( + id: 'dark_theme', + description: 'theme de couleur orange', + data: appTheme.darkTheme, + ), + AppTheme( + id: 'orange_theme', + description: 'theme de couleur orange', + data: appTheme.orangeTheme, + ), + AppTheme( + id: 'blue_theme', + description: 'theme de couleur orange', + data: appTheme.blueTheme, + ), + AppTheme( + id: 'green_theme', + description: 'theme de couleur orange', + data: appTheme.greenTheme, + ), + AppTheme( + id: 'brown_theme', + description: 'theme de couleur orange', + data: appTheme.brownTheme, + ), + AppTheme( + id: 'purple_theme', + description: 'theme de couleur orange', + data: appTheme.purlpleTheme, + ), + ], + child: ThemeConsumer( + child: Builder( + builder: (themeContext) { + return MaterialApp( + title: 'DOMINICK', + debugShowCheckedModeBanner: false, + theme: ThemeProvider.themeOf(themeContext).data, + home: const HomePage(), + ); + }, + ), + ), + ), + ); + } +} diff --git a/lib/core/theme/app_theme.dart b/lib/core/theme/app_theme.dart index 7d8c9cd..1e077ef 100644 --- a/lib/core/theme/app_theme.dart +++ b/lib/core/theme/app_theme.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'app_color.dart'; -class AppTheme { +class ApplicationTheme { final BuildContext context; - AppTheme(this.context); + ApplicationTheme(this.context); AppColors colors(context) => Theme.of(context).extension()!; diff --git a/lib/core/utils/sizes/responsive.dart b/lib/core/utils/sizes/responsive.dart index 349723a..9d4c23a 100644 --- a/lib/core/utils/sizes/responsive.dart +++ b/lib/core/utils/sizes/responsive.dart @@ -74,8 +74,10 @@ class ResponsiveSize { return tablet; } else if (size.width >= 500) { return mobileLarge; - } else if (size.width >= 300) { - return small ?? mobile; + } else if (size.width >= 390) { + return mobile; + } else if (small != null && size.width >= 300) { + return small; } else { return mobile; } diff --git a/lib/main.dart b/lib/main.dart index dffd908..d545ee8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,15 +1,8 @@ -import 'package:bamboo/foundation/breakpoint.dart'; import 'package:device_preview/device_preview.dart'; import 'package:flutter/material.dart'; -import 'package:meta_seo/meta_seo.dart'; -import 'package:flutter/foundation.dart'; -import 'core/theme/app_theme.dart'; -import 'pages/home/home.dart'; +import 'app.dart'; void main() { - if (kIsWeb) { - MetaSEO().config(); - } runApp( DevicePreview( enabled: false, @@ -17,24 +10,3 @@ void main() { ), ); } - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - // This widget is the root of your application. - @override - Widget build(BuildContext context) { - AppTheme appTheme = AppTheme(context); - return BambooBreakPoint( - mobile: 576, - tablet: 768, - desktop: 1024, - child: MaterialApp( - title: 'DOMINICK', - debugShowCheckedModeBanner: false, - theme: appTheme.greenTheme, - home: const HomePage(), - ), - ); - } -} diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index c11b920..617a437 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -8,6 +8,7 @@ import 'parts/footer/footer_v2.dart'; import 'parts/part.dart'; // ignore: unused_import import 'parts/widgets/app_bar.dart'; +import 'parts/widgets/floating_btt.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @@ -40,6 +41,9 @@ class _HomePageState extends State { // appBar: AppBarWidget( // controller: _scrollController, // ), + floatingActionButton: FloatingColorBtt( + controller: _scrollController, + ), body: Container( color: Colors.grey.shade900, child: Container( diff --git a/lib/pages/home/parts/footer/footer_v2.dart b/lib/pages/home/parts/footer/footer_v2.dart index 14fede7..359cbdf 100644 --- a/lib/pages/home/parts/footer/footer_v2.dart +++ b/lib/pages/home/parts/footer/footer_v2.dart @@ -6,6 +6,7 @@ import '../../../../core/theme/app_color.dart'; import '../../../../data/image_assets.dart'; import '../../../../data/social_media.dart'; import '../../../../models/social_media_model.dart'; +import '../widgets/icon_and_title_widet.dart'; import '../widgets/my_footer_widget.dart'; class FooterPartV2 extends StatelessWidget { @@ -16,8 +17,8 @@ class FooterPartV2 extends StatelessWidget { final themeColor = Theme.of(context).extension()!; double textSize = ResponsiveSize.number( context: context, - small: 10, - mobile: 12, + // small: 15, + mobile: 15, tablet: 20, mobileLarge: 15, desktop: 20, @@ -36,6 +37,7 @@ class FooterPartV2 extends StatelessWidget { width: MediaQuery.sizeOf(context).width, height: ResponsiveSize.number( context: context, + small: MediaQuery.sizeOf(context).height * .3, mobile: MediaQuery.sizeOf(context).height * .25, tablet: 340, mobileLarge: MediaQuery.sizeOf(context).height * .6, @@ -46,33 +48,20 @@ class FooterPartV2 extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Expanded( - flex: 2, - child: Container( - // height: imageSize, - margin: EdgeInsets.symmetric( - horizontal: ResponsiveSize.number( - context: context, - mobile: 20, - tablet: 20, - mobileLarge: 10, - desktop: 30, - ), - ), - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage( - imageAsset.cekahLogo, - ), - fit: BoxFit.fitWidth, - ), - ), + Responsive( + mobile: const SizedBox(), + desktop: logoPart( + context: context, + themeColor: themeColor, + ), + tablet: logoPart( + context: context, + themeColor: themeColor, + ), + mobileLarge: logoPart( + context: context, + themeColor: themeColor, ), - ), - VerticalDivider( - color: themeColor.whiteColor, - width: 2, - thickness: 1, ), Expanded( flex: 4, @@ -91,21 +80,9 @@ class FooterPartV2 extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - child: Text( - 'Mes coordonnées :', - style: TextStyle( - color: themeColor.whiteColor, - fontSize: ResponsiveSize.number( - context: context, - mobile: 25, - desktop: 40, - mobileLarge: 40, - tablet: 40, - ), - fontWeight: FontWeight.normal, - ), - ), + const BigTitileWidget( + title: 'Mes coordonnées :', + svgIcon: '', ), Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -156,6 +133,46 @@ class FooterPartV2 extends StatelessWidget { ); } + Widget logoPart({ + required BuildContext context, + required AppColors themeColor, + }) { + return Expanded( + flex: 2, + child: Row( + children: [ + Expanded( + child: Container( + // height: imageSize, + margin: EdgeInsets.symmetric( + horizontal: ResponsiveSize.number( + context: context, + mobile: 20, + tablet: 20, + mobileLarge: 10, + desktop: 30, + ), + ), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + imageAsset.cekahLogo, + ), + fit: BoxFit.fitWidth, + ), + ), + ), + ), + VerticalDivider( + color: themeColor.whiteColor, + width: 2, + thickness: 1, + ), + ], + ), + ); + } + Widget buildContactInfo({ required IconData icon, required String text, @@ -166,7 +183,13 @@ class FooterPartV2 extends StatelessWidget { return Container( padding: const EdgeInsets.symmetric(vertical: 5), // height: 50, - width: MediaQuery.sizeOf(context).width * .5, + width: ResponsiveSize.number( + context: context, + mobile: MediaQuery.sizeOf(context).width, + tablet: MediaQuery.sizeOf(context).width * .5, + mobileLarge: MediaQuery.sizeOf(context).height * .5, + desktop: MediaQuery.sizeOf(context).width * .5, + ), child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, diff --git a/lib/pages/home/parts/myteam/teams.dart b/lib/pages/home/parts/myteam/teams.dart index 9bc127e..4619299 100644 --- a/lib/pages/home/parts/myteam/teams.dart +++ b/lib/pages/home/parts/myteam/teams.dart @@ -30,7 +30,7 @@ class MyBigPart extends StatelessWidget { child: Column( children: [ const BigTitileWidget( - title: 'Notre équipe', + title: 'Mon équipe', svgIcon: 'team', ), SizedBox( diff --git a/lib/pages/home/parts/skills/skills.dart b/lib/pages/home/parts/skills/skills.dart index 75ea63e..7a7a6cb 100644 --- a/lib/pages/home/parts/skills/skills.dart +++ b/lib/pages/home/parts/skills/skills.dart @@ -17,11 +17,13 @@ class SkillsPart extends StatelessWidget { margin: EdgeInsets.symmetric( horizontal: ResponsiveSize.number( context: context, - mobile: 5, - desktop: MediaQuery.sizeOf(context).width * .2, - mobileLarge: 50, - tablet: 40, + small: 0, + mobile: MediaQuery.sizeOf(context).width * .1, + desktop: MediaQuery.sizeOf(context).width * .1, + mobileLarge: MediaQuery.sizeOf(context).width * .1, + tablet: MediaQuery.sizeOf(context).width * .1, ), + // horizontal: 0, vertical: ResponsiveSize.number( context: context, mobile: 10, @@ -32,10 +34,11 @@ class SkillsPart extends StatelessWidget { ), height: ResponsiveSize.number( context: context, - mobile: 450, - tablet: 700, + // small: 710, + mobile: 610, + tablet: 550, mobileLarge: 400, - desktop: 550, + desktop: 630, ), child: Column( children: [ @@ -46,7 +49,7 @@ class SkillsPart extends StatelessWidget { Expanded( child: ResponsiveGridList( squareCells: false, - scroll: true, + scroll: false, rowMainAxisAlignment: MainAxisAlignment.center, desiredItemWidth: ResponsiveSize.number( context: context, @@ -116,7 +119,7 @@ class SkillsPart extends StatelessWidget { style: TextStyle( fontSize: ResponsiveSize.number( context: context, - mobile: 13, + mobile: 12, tablet: 13, mobileLarge: 13, desktop: 15, @@ -142,9 +145,9 @@ class SkillsPart extends StatelessWidget { List skills = [ SkillModel(name: 'Dart', percentage: 0.75), SkillModel(name: 'Flutter', percentage: 0.85), - // Skill(name: 'Flutter Bloc', percentage: 0.7), SkillModel(name: 'Clean Archi', percentage: 0.9), SkillModel(name: 'CI/CD', percentage: 0.4), + SkillModel(name: 'PocketBase', percentage: 0.5), SkillModel(name: 'Firebase', percentage: 0.5), SkillModel(name: 'Golang', percentage: 0.25), ]; diff --git a/lib/pages/home/parts/widgets/floating_btt.dart b/lib/pages/home/parts/widgets/floating_btt.dart new file mode 100644 index 0000000..4826ac1 --- /dev/null +++ b/lib/pages/home/parts/widgets/floating_btt.dart @@ -0,0 +1,112 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'package:scroll_vanisher/scroll_vanisher.dart'; +import 'package:theme_provider/theme_provider.dart'; +import 'package:unicons/unicons.dart'; + +import '../../../../core/theme/app_color.dart'; + +class FloatingColorBtt extends StatefulWidget { + final ScrollController controller; + const FloatingColorBtt({super.key, required this.controller}); + + @override + State createState() => _FloatingColorBttState(); +} + +class _FloatingColorBttState extends State { + ValueNotifier isDialOpen = ValueNotifier(false); + @override + Widget build(BuildContext context) { + final themeColor = Theme.of(context).extension()!; + + return ScrollVanisher( + controller: widget.controller, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: SpeedDial( + buttonSize: const Size(40, 40), + childMargin: EdgeInsets.symmetric(horizontal: 10), + overlayColor: Colors.black, + childrenButtonSize: const Size(40, 50), + backgroundColor: themeColor.secondaryColor, + openCloseDial: isDialOpen, + onPress: () { + isDialOpen.value = !isDialOpen.value; + }, + children: [ + childDial( + color: const Color(0xffFE5944), + themeId: 'orange_theme', + title: 'Theme Orange', + ), + childDial( + color: const Color(0xff537EC5), + themeId: 'blue_theme', + title: 'Theme bleu', + ), + childDial( + color: const Color(0xff222831), + themeId: 'dark_theme', + title: 'Theme sombre', + ), + childDial( + color: const Color(0xff4E9F3D), + themeId: 'green_theme', + title: 'Theme verte', + ), + childDial( + color: const Color(0xff3E3232), + themeId: 'brown_theme', + title: 'Theme brun', + ), + childDial( + color: Colors.purple, + themeId: 'purple_theme', + title: 'Theme violet', + ), + ], + child: Icon( + UniconsLine.palette, + color: themeColor.tertioColor, + ), + ), + // child: FloatingActionButton( + // onPressed: () {}, + // backgroundColor: themeColor.secondaryColor, + // materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(50), + // ), + // child: Icon( + // UniconsLine.palette, + // color: themeColor.tertioColor, + // ), + // ), + ), + ); + } + + SpeedDialChild childDial({ + required String title, + required Color color, + required String themeId, + }) { + return SpeedDialChild( + label: title, + labelStyle: const TextStyle( + fontFamily: 'Product sans', + fontWeight: FontWeight.bold, + ), + backgroundColor: color, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + elevation: 0, + child: const SizedBox(), + onTap: () { + ThemeProvider.controllerOf(context).setTheme(themeId); + }, + ); + } +} diff --git a/lib/pages/home/parts/widgets/icon_and_title_widet.dart b/lib/pages/home/parts/widgets/icon_and_title_widet.dart index 79e9dff..7a39cdb 100644 --- a/lib/pages/home/parts/widgets/icon_and_title_widet.dart +++ b/lib/pages/home/parts/widgets/icon_and_title_widet.dart @@ -38,28 +38,32 @@ class BigTitileWidget extends StatelessWidget { // ), child: Column( mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: svgIcon.isNotEmpty + ? CrossAxisAlignment.center + : CrossAxisAlignment.start, children: [ - SizedBox( - width: MediaQuery.sizeOf(context).width, - child: SvgPicture.asset( - '${imageAsset.directory}/icon/$svgIcon.svg', - width: Bamboo.number( - context: context, - mobile: 30, - tablet: 50, - desktop: 50, - unit: Unit.px, - ), - colorFilter: ColorFilter.mode( - themeColor.whiteColor ?? Colors.white, - BlendMode.srcIn, + if (svgIcon.isNotEmpty) + SizedBox( + width: MediaQuery.sizeOf(context).width, + child: SvgPicture.asset( + '${imageAsset.directory}/icon/$svgIcon.svg', + width: Bamboo.number( + context: context, + mobile: 30, + tablet: 50, + desktop: 50, + unit: Unit.px, + ), + colorFilter: ColorFilter.mode( + themeColor.whiteColor ?? Colors.white, + BlendMode.srcIn, + ), ), ), - ), SizedBox( height: Bamboo.number( context: context, - mobile: 50, + mobile: svgIcon.isNotEmpty ? 50 : 30, tablet: 50, desktop: 70, unit: Unit.px, diff --git a/pubspec.lock b/pubspec.lock index fc07538..c6ac7a7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -155,6 +155,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_speed_dial: + dependency: "direct main" + description: + name: flutter_speed_dial + sha256: "698a037274a66dbae8697c265440e6acb6ab6cae9ac5f95c749e7944d8f28d41" + url: "https://pub.dev" + source: hosted + version: "7.0.0" flutter_svg: dependency: "direct main" description: @@ -482,6 +490,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.1" + theme_provider: + dependency: "direct main" + description: + name: theme_provider + sha256: "6a2839ee1bd539ceb789f25ea9696fe90f9dfad28e3228f209b8ff9255c58099" + url: "https://pub.dev" + source: hosted + version: "0.6.0" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index accbd03..63ac7d9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,8 @@ dependencies: meta_seo: ^3.0.9 percent_indicator: ^4.2.3 responsive_grid: ^2.4.4 + theme_provider: ^0.6.0 + flutter_speed_dial: ^7.0.0 dependency_overrides: web: ^0.5.1 diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index 8072559..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:dominick/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}