diff --git a/.idea/Motula-Translate-App.iml b/.idea/Motula-Translate-App.iml index 2d7b4cc..3e245fa 100644 --- a/.idea/Motula-Translate-App.iml +++ b/.idea/Motula-Translate-App.iml @@ -9,5 +9,7 @@ + + \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml new file mode 100644 index 0000000..2a0027a --- /dev/null +++ b/.idea/libraries/Dart_Packages.xml @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml new file mode 100644 index 0000000..3c407c5 --- /dev/null +++ b/.idea/libraries/Dart_SDK.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 639900d..2c9733a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,5 @@ - - + \ No newline at end of file diff --git a/motula_translate_app/android/settings.gradle b/motula_translate_app/android/settings.gradle index 1d6d19b..6935726 100644 --- a/motula_translate_app/android/settings.gradle +++ b/motula_translate_app/android/settings.gradle @@ -23,4 +23,4 @@ plugins { id "org.jetbrains.kotlin.android" version "1.7.10" apply false } -include ":app" + diff --git a/motula_translate_app/assets/Backgrounds/Spline.png b/motula_translate_app/assets/Backgrounds/Spline.png new file mode 100644 index 0000000..e84ec0e Binary files /dev/null and b/motula_translate_app/assets/Backgrounds/Spline.png differ diff --git a/motula_translate_app/assets/Fonts/Inter-Regular.ttf b/motula_translate_app/assets/Fonts/Inter-Regular.ttf new file mode 100644 index 0000000..cc73944 Binary files /dev/null and b/motula_translate_app/assets/Fonts/Inter-Regular.ttf differ diff --git a/motula_translate_app/assets/Fonts/Inter-SemiBold.ttf b/motula_translate_app/assets/Fonts/Inter-SemiBold.ttf new file mode 100644 index 0000000..278ceaa Binary files /dev/null and b/motula_translate_app/assets/Fonts/Inter-SemiBold.ttf differ diff --git a/motula_translate_app/assets/Fonts/Poppins-Bold.ttf b/motula_translate_app/assets/Fonts/Poppins-Bold.ttf new file mode 100644 index 0000000..00559ee Binary files /dev/null and b/motula_translate_app/assets/Fonts/Poppins-Bold.ttf differ diff --git a/motula_translate_app/assets/RiveAssets/button.riv b/motula_translate_app/assets/RiveAssets/button.riv new file mode 100644 index 0000000..f3130b7 Binary files /dev/null and b/motula_translate_app/assets/RiveAssets/button.riv differ diff --git a/motula_translate_app/assets/RiveAssets/check.riv b/motula_translate_app/assets/RiveAssets/check.riv new file mode 100644 index 0000000..8c0e1b1 Binary files /dev/null and b/motula_translate_app/assets/RiveAssets/check.riv differ diff --git a/motula_translate_app/assets/RiveAssets/confetti.riv b/motula_translate_app/assets/RiveAssets/confetti.riv new file mode 100644 index 0000000..221714d Binary files /dev/null and b/motula_translate_app/assets/RiveAssets/confetti.riv differ diff --git a/motula_translate_app/assets/RiveAssets/house.riv b/motula_translate_app/assets/RiveAssets/house.riv new file mode 100644 index 0000000..bcbd285 Binary files /dev/null and b/motula_translate_app/assets/RiveAssets/house.riv differ diff --git a/motula_translate_app/assets/RiveAssets/icons.riv b/motula_translate_app/assets/RiveAssets/icons.riv new file mode 100644 index 0000000..26ccc6c Binary files /dev/null and b/motula_translate_app/assets/RiveAssets/icons.riv differ diff --git a/motula_translate_app/assets/RiveAssets/menu_button.riv b/motula_translate_app/assets/RiveAssets/menu_button.riv new file mode 100644 index 0000000..2b66261 Binary files /dev/null and b/motula_translate_app/assets/RiveAssets/menu_button.riv differ diff --git a/motula_translate_app/assets/RiveAssets/shapes.riv b/motula_translate_app/assets/RiveAssets/shapes.riv new file mode 100644 index 0000000..0c9cf5f Binary files /dev/null and b/motula_translate_app/assets/RiveAssets/shapes.riv differ diff --git a/motula_translate_app/assets/avaters/Avatar 1.jpg b/motula_translate_app/assets/avaters/Avatar 1.jpg new file mode 100644 index 0000000..e72ded0 Binary files /dev/null and b/motula_translate_app/assets/avaters/Avatar 1.jpg differ diff --git a/motula_translate_app/assets/avaters/Avatar 2.jpg b/motula_translate_app/assets/avaters/Avatar 2.jpg new file mode 100644 index 0000000..f828aac Binary files /dev/null and b/motula_translate_app/assets/avaters/Avatar 2.jpg differ diff --git a/motula_translate_app/assets/avaters/Avatar 3.jpg b/motula_translate_app/assets/avaters/Avatar 3.jpg new file mode 100644 index 0000000..8bcf99f Binary files /dev/null and b/motula_translate_app/assets/avaters/Avatar 3.jpg differ diff --git a/motula_translate_app/assets/avaters/Avatar 4.jpg b/motula_translate_app/assets/avaters/Avatar 4.jpg new file mode 100644 index 0000000..b0022b8 Binary files /dev/null and b/motula_translate_app/assets/avaters/Avatar 4.jpg differ diff --git a/motula_translate_app/assets/avaters/Avatar 5.jpg b/motula_translate_app/assets/avaters/Avatar 5.jpg new file mode 100644 index 0000000..44c70ef Binary files /dev/null and b/motula_translate_app/assets/avaters/Avatar 5.jpg differ diff --git a/motula_translate_app/assets/avaters/Avatar 6.jpg b/motula_translate_app/assets/avaters/Avatar 6.jpg new file mode 100644 index 0000000..fc227bd Binary files /dev/null and b/motula_translate_app/assets/avaters/Avatar 6.jpg differ diff --git a/motula_translate_app/assets/avaters/Avatar Default.jpg b/motula_translate_app/assets/avaters/Avatar Default.jpg new file mode 100644 index 0000000..e8cf8d2 Binary files /dev/null and b/motula_translate_app/assets/avaters/Avatar Default.jpg differ diff --git a/motula_translate_app/assets/icons/Arrow Right.svg b/motula_translate_app/assets/icons/Arrow Right.svg new file mode 100644 index 0000000..0b65734 --- /dev/null +++ b/motula_translate_app/assets/icons/Arrow Right.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/motula_translate_app/assets/icons/User.svg b/motula_translate_app/assets/icons/User.svg new file mode 100644 index 0000000..81a4aa3 --- /dev/null +++ b/motula_translate_app/assets/icons/User.svg @@ -0,0 +1,4 @@ + + + + diff --git a/motula_translate_app/assets/icons/apple_box.svg b/motula_translate_app/assets/icons/apple_box.svg new file mode 100644 index 0000000..f33beee --- /dev/null +++ b/motula_translate_app/assets/icons/apple_box.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/motula_translate_app/assets/icons/code.svg b/motula_translate_app/assets/icons/code.svg new file mode 100644 index 0000000..d3c6508 --- /dev/null +++ b/motula_translate_app/assets/icons/code.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/motula_translate_app/assets/icons/email.svg b/motula_translate_app/assets/icons/email.svg new file mode 100644 index 0000000..c302586 --- /dev/null +++ b/motula_translate_app/assets/icons/email.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/motula_translate_app/assets/icons/email_box.svg b/motula_translate_app/assets/icons/email_box.svg new file mode 100644 index 0000000..5105642 --- /dev/null +++ b/motula_translate_app/assets/icons/email_box.svg @@ -0,0 +1,4 @@ + + + + diff --git a/motula_translate_app/assets/icons/google_box.svg b/motula_translate_app/assets/icons/google_box.svg new file mode 100644 index 0000000..7568034 --- /dev/null +++ b/motula_translate_app/assets/icons/google_box.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/motula_translate_app/assets/icons/ios.svg b/motula_translate_app/assets/icons/ios.svg new file mode 100644 index 0000000..0160a1e --- /dev/null +++ b/motula_translate_app/assets/icons/ios.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/motula_translate_app/assets/icons/password.svg b/motula_translate_app/assets/icons/password.svg new file mode 100644 index 0000000..f3b98e8 --- /dev/null +++ b/motula_translate_app/assets/icons/password.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/motula_translate_app/assets/icons/profile_img.png b/motula_translate_app/assets/icons/profile_img.png new file mode 100644 index 0000000..7f595a0 Binary files /dev/null and b/motula_translate_app/assets/icons/profile_img.png differ diff --git a/motula_translate_app/lib/constants.dart b/motula_translate_app/lib/constants.dart new file mode 100644 index 0000000..2a8cb11 --- /dev/null +++ b/motula_translate_app/lib/constants.dart @@ -0,0 +1,7 @@ +import 'package:flutter/material.dart'; + +const Color backgroundColor2 = Color(0xFF17203A); +const Color backgroundColorLight = Color(0xFFF2F6FF); +const Color backgroundColorDark = Color(0xFF25254B); +const Color shadowColorLight = Color(0xFF4A5367); +const Color shadowColorDark = Colors.black; diff --git a/motula_translate_app/lib/main.dart b/motula_translate_app/lib/main.dart index 8e94089..0acefc2 100644 --- a/motula_translate_app/lib/main.dart +++ b/motula_translate_app/lib/main.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:motula_translate_app/screens/onboding/onboding_screen.dart'; void main() { runApp(const MyApp()); @@ -11,115 +12,33 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', + title: 'The Flutter Way', theme: ThemeData( - // This is the theme of your application. - // - // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a purple toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. - colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), - useMaterial3: true, - ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), - ); - } -} - -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - final String title; - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // TRY THIS: Try changing the color here to a specific color (to - // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar - // change color while the other colors stay the same. - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - // - // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" - // action in the IDE, or press "p" in the console), to see the - // wireframe for each widget. - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, - ), - ], + scaffoldBackgroundColor: const Color(0xFFEEF1F8), + primarySwatch: Colors.blue, + fontFamily: "Intel", + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom(foregroundColor: Colors.white), + ), + inputDecorationTheme: const InputDecorationTheme( + filled: true, + fillColor: Colors.white, + errorStyle: TextStyle(height: 0), + border: defaultInputBorder, + enabledBorder: defaultInputBorder, + focusedBorder: defaultInputBorder, + errorBorder: defaultInputBorder, ), ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), - ), // This trailing comma makes auto-formatting nicer for build methods. + home: const OnbodingScreen(), ); } } + +const defaultInputBorder = OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(16)), + borderSide: BorderSide( + color: Color(0xFFDEE3F2), + width: 1, + ), +); diff --git a/motula_translate_app/lib/model/course.dart b/motula_translate_app/lib/model/course.dart new file mode 100644 index 0000000..183677c --- /dev/null +++ b/motula_translate_app/lib/model/course.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart' show Color; + +class Course { + final String title, description, iconSrc; + final Color color; + + Course({ + required this.title, + this.description = 'Build and animate an iOS app from scratch', + this.iconSrc = "assets/icons/ios.svg", + this.color = const Color(0xFF7553F6), + }); +} + +final List courses = [ + Course( + title: "Animations in SwiftUI", + ), + Course( + title: "Animations in Flutter", + iconSrc: "assets/icons/code.svg", + color: const Color(0xFF80A4FF), + ), +]; + +final List recentCourses = [ + Course(title: "State Machine"), + Course( + title: "Animated Menu", + color: const Color(0xFF9CC5FF), + iconSrc: "assets/icons/code.svg", + ), + Course(title: "Flutter with Rive"), + Course( + title: "Animated Menu", + color: const Color(0xFF9CC5FF), + iconSrc: "assets/icons/code.svg", + ), +]; diff --git a/motula_translate_app/lib/model/menu.dart b/motula_translate_app/lib/model/menu.dart new file mode 100644 index 0000000..710988e --- /dev/null +++ b/motula_translate_app/lib/model/menu.dart @@ -0,0 +1,93 @@ +import 'rive_model.dart'; + +class Menu { + final String title; + final RiveModel rive; + + Menu({required this.title, required this.rive}); +} + +List sidebarMenus = [ + Menu( + title: "Home", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "HOME", + stateMachineName: "HOME_interactivity"), + ), + Menu( + title: "Search", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "SEARCH", + stateMachineName: "SEARCH_Interactivity"), + ), + Menu( + title: "Favorites", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "LIKE/STAR", + stateMachineName: "STAR_Interactivity"), + ), + Menu( + title: "Help", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "CHAT", + stateMachineName: "CHAT_Interactivity"), + ), +]; +List sidebarMenus2 = [ + Menu( + title: "History", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "TIMER", + stateMachineName: "TIMER_Interactivity"), + ), + Menu( + title: "Notifications", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "BELL", + stateMachineName: "BELL_Interactivity"), + ), +]; + +List bottomNavItems = [ + Menu( + title: "Chat", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "CHAT", + stateMachineName: "CHAT_Interactivity"), + ), + Menu( + title: "Search", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "SEARCH", + stateMachineName: "SEARCH_Interactivity"), + ), + Menu( + title: "Timer", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "TIMER", + stateMachineName: "TIMER_Interactivity"), + ), + Menu( + title: "Notification", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "BELL", + stateMachineName: "BELL_Interactivity"), + ), + Menu( + title: "Profile", + rive: RiveModel( + src: "assets/RiveAssets/icons.riv", + artboard: "USER", + stateMachineName: "USER_Interactivity"), + ), +]; diff --git a/motula_translate_app/lib/model/rive_model.dart b/motula_translate_app/lib/model/rive_model.dart new file mode 100644 index 0000000..6f6c73e --- /dev/null +++ b/motula_translate_app/lib/model/rive_model.dart @@ -0,0 +1,17 @@ +import 'package:rive/rive.dart'; + +class RiveModel { + final String src, artboard, stateMachineName; + late SMIBool? status; + + RiveModel({ + required this.src, + required this.artboard, + required this.stateMachineName, + this.status, + }); + + set setStatus(SMIBool state) { + status = state; + } +} diff --git a/motula_translate_app/lib/screens/entryPoint/components/animated_bar.dart b/motula_translate_app/lib/screens/entryPoint/components/animated_bar.dart new file mode 100644 index 0000000..2818d1c --- /dev/null +++ b/motula_translate_app/lib/screens/entryPoint/components/animated_bar.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +class AnimatedBar extends StatelessWidget { + const AnimatedBar({ + Key? key, + required this.isActive, + }) : super(key: key); + + final bool isActive; + + @override + Widget build(BuildContext context) { + return AnimatedContainer( + margin: const EdgeInsets.only(bottom: 2), + duration: const Duration(milliseconds: 200), + height: 4, + width: isActive ? 20 : 0, + decoration: const BoxDecoration( + color: Color(0xFF81B4FF), + borderRadius: BorderRadius.all( + Radius.circular(12), + )), + ); + } +} diff --git a/motula_translate_app/lib/screens/entryPoint/components/btm_nav_item.dart b/motula_translate_app/lib/screens/entryPoint/components/btm_nav_item.dart new file mode 100644 index 0000000..eed2f06 --- /dev/null +++ b/motula_translate_app/lib/screens/entryPoint/components/btm_nav_item.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; + +import '../../../model/menu.dart'; +import 'animated_bar.dart'; + +class BtmNavItem extends StatelessWidget { + const BtmNavItem( + {super.key, + required this.navBar, + required this.press, + required this.riveOnInit, + required this.selectedNav}); + + final Menu navBar; + final VoidCallback press; + final ValueChanged riveOnInit; + final Menu selectedNav; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: press, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + AnimatedBar(isActive: selectedNav == navBar), + SizedBox( + height: 36, + width: 36, + child: Opacity( + opacity: selectedNav == navBar ? 1 : 0.5, + child: RiveAnimation.asset( + navBar.rive.src, + artboard: navBar.rive.artboard, + onInit: riveOnInit, + ), + ), + ), + ], + ), + ); + } +} diff --git a/motula_translate_app/lib/screens/entryPoint/components/info_card.dart b/motula_translate_app/lib/screens/entryPoint/components/info_card.dart new file mode 100644 index 0000000..d90d0ae --- /dev/null +++ b/motula_translate_app/lib/screens/entryPoint/components/info_card.dart @@ -0,0 +1,33 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class InfoCard extends StatelessWidget { + const InfoCard({ + Key? key, + required this.name, + required this.bio, + }) : super(key: key); + + final String name, bio; + + @override + Widget build(BuildContext context) { + return ListTile( + leading: const CircleAvatar( + backgroundColor: Colors.white24, + child: Icon( + CupertinoIcons.person, + color: Colors.white, + ), + ), + title: Text( + name, + style: const TextStyle(color: Colors.white), + ), + subtitle: Text( + bio, + style: const TextStyle(color: Colors.white70), + ), + ); + } +} diff --git a/motula_translate_app/lib/screens/entryPoint/components/menu_btn.dart b/motula_translate_app/lib/screens/entryPoint/components/menu_btn.dart new file mode 100644 index 0000000..485c4a5 --- /dev/null +++ b/motula_translate_app/lib/screens/entryPoint/components/menu_btn.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; + +class MenuBtn extends StatelessWidget { + const MenuBtn({super.key, required this.press, required this.riveOnInit}); + + final VoidCallback press; + final ValueChanged riveOnInit; + + @override + Widget build(BuildContext context) { + return SafeArea( + child: GestureDetector( + onTap: press, + child: Container( + margin: const EdgeInsets.only(left: 12), + height: 40, + width: 40, + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black12, + offset: Offset(0, 3), + blurRadius: 8, + ), + ], + ), + child: RiveAnimation.asset( + "assets/RiveAssets/menu_button.riv", + onInit: riveOnInit, + ), + ), + ), + ); + } +} diff --git a/motula_translate_app/lib/screens/entryPoint/components/side_bar.dart b/motula_translate_app/lib/screens/entryPoint/components/side_bar.dart new file mode 100644 index 0000000..566238d --- /dev/null +++ b/motula_translate_app/lib/screens/entryPoint/components/side_bar.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; + +import '../../../model/menu.dart'; +import '../../../utils/rive_utils.dart'; +import 'info_card.dart'; +import 'side_menu.dart'; + +class SideBar extends StatefulWidget { + const SideBar({super.key}); + + @override + State createState() => _SideBarState(); +} + +class _SideBarState extends State { + Menu selectedSideMenu = sidebarMenus.first; + @override + Widget build(BuildContext context) { + return SafeArea( + child: Container( + width: 288, + height: double.infinity, + decoration: const BoxDecoration( + color: Color(0xFF17203A), + borderRadius: BorderRadius.all( + Radius.circular(30), + ), + ), + child: DefaultTextStyle( + style: const TextStyle(color: Colors.white), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const InfoCard( + name: "Abu Anwar", + bio: "YouTuber", + ), + Padding( + padding: const EdgeInsets.only(left: 24, top: 32, bottom: 16), + child: Text( + "Browse".toUpperCase(), + style: Theme.of(context) + .textTheme + .titleMedium! + .copyWith(color: Colors.white70), + ), + ), + ...sidebarMenus + .map((menu) => SideMenu( + menu: menu, + selectedMenu: selectedSideMenu, + press: () { + RiveUtils.chnageSMIBoolState(menu.rive.status!); + setState(() { + selectedSideMenu = menu; + }); + }, + riveOnInit: (artboard) { + menu.rive.status = RiveUtils.getRiveInput(artboard, + stateMachineName: menu.rive.stateMachineName); + }, + )) + .toList(), + Padding( + padding: const EdgeInsets.only(left: 24, top: 40, bottom: 16), + child: Text( + "History".toUpperCase(), + style: Theme.of(context) + .textTheme + .titleMedium! + .copyWith(color: Colors.white70), + ), + ), + ...sidebarMenus2 + .map((menu) => SideMenu( + menu: menu, + selectedMenu: selectedSideMenu, + press: () { + RiveUtils.chnageSMIBoolState(menu.rive.status!); + setState(() { + selectedSideMenu = menu; + }); + }, + riveOnInit: (artboard) { + menu.rive.status = RiveUtils.getRiveInput(artboard, + stateMachineName: menu.rive.stateMachineName); + }, + )) + .toList(), + ], + ), + ), + ), + ); + } +} diff --git a/motula_translate_app/lib/screens/entryPoint/components/side_menu.dart b/motula_translate_app/lib/screens/entryPoint/components/side_menu.dart new file mode 100644 index 0000000..489252e --- /dev/null +++ b/motula_translate_app/lib/screens/entryPoint/components/side_menu.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; + +import '../../../model/menu.dart'; + +class SideMenu extends StatelessWidget { + const SideMenu( + {super.key, + required this.menu, + required this.press, + required this.riveOnInit, + required this.selectedMenu}); + + final Menu menu; + final VoidCallback press; + final ValueChanged riveOnInit; + final Menu selectedMenu; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + const Padding( + padding: EdgeInsets.only(left: 24), + child: Divider(color: Colors.white24, height: 1), + ), + Stack( + children: [ + AnimatedPositioned( + duration: const Duration(milliseconds: 300), + curve: Curves.fastOutSlowIn, + width: selectedMenu == menu ? 288 : 0, + height: 56, + left: 0, + child: Container( + decoration: const BoxDecoration( + color: Color(0xFF6792FF), + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + ), + ), + ListTile( + onTap: press, + leading: SizedBox( + height: 36, + width: 36, + child: RiveAnimation.asset( + menu.rive.src, + artboard: menu.rive.artboard, + onInit: riveOnInit, + ), + ), + title: Text( + menu.title, + style: const TextStyle(color: Colors.white), + ), + ), + ], + ), + ], + ); + } +} \ No newline at end of file diff --git a/motula_translate_app/lib/screens/entryPoint/entry_point.dart b/motula_translate_app/lib/screens/entryPoint/entry_point.dart new file mode 100644 index 0000000..6138531 --- /dev/null +++ b/motula_translate_app/lib/screens/entryPoint/entry_point.dart @@ -0,0 +1,181 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; +import 'package:motula_translate_app/constants.dart'; +import 'package:motula_translate_app/screens/home/home_screen.dart'; +import 'package:motula_translate_app/utils/rive_utils.dart'; + +import '../../model/menu.dart'; +import 'components/btm_nav_item.dart'; +import 'components/menu_btn.dart'; +import 'components/side_bar.dart'; + +class EntryPoint extends StatefulWidget { + const EntryPoint({super.key}); + + @override + State createState() => _EntryPointState(); +} + +class _EntryPointState extends State + with SingleTickerProviderStateMixin { + bool isSideBarOpen = false; + + Menu selectedBottonNav = bottomNavItems.first; + Menu selectedSideMenu = sidebarMenus.first; + + late SMIBool isMenuOpenInput; + + void updateSelectedBtmNav(Menu menu) { + if (selectedBottonNav != menu) { + setState(() { + selectedBottonNav = menu; + }); + } + } + + late AnimationController _animationController; + late Animation scalAnimation; + late Animation animation; + + @override + void initState() { + _animationController = AnimationController( + vsync: this, duration: const Duration(milliseconds: 200)) + ..addListener( + () { + setState(() {}); + }, + ); + scalAnimation = Tween(begin: 1, end: 0.8).animate(CurvedAnimation( + parent: _animationController, curve: Curves.fastOutSlowIn)); + animation = Tween(begin: 0, end: 1).animate(CurvedAnimation( + parent: _animationController, curve: Curves.fastOutSlowIn)); + super.initState(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + extendBody: true, + resizeToAvoidBottomInset: false, + backgroundColor: backgroundColor2, + body: Stack( + children: [ + AnimatedPositioned( + width: 288, + height: MediaQuery.of(context).size.height, + duration: const Duration(milliseconds: 200), + curve: Curves.fastOutSlowIn, + left: isSideBarOpen ? 0 : -288, + top: 0, + child: const SideBar(), + ), + Transform( + alignment: Alignment.center, + transform: Matrix4.identity() + ..setEntry(3, 2, 0.001) + ..rotateY( + 1 * animation.value - 30 * (animation.value) * pi / 180), + child: Transform.translate( + offset: Offset(animation.value * 265, 0), + child: Transform.scale( + scale: scalAnimation.value, + child: const ClipRRect( + borderRadius: BorderRadius.all( + Radius.circular(24), + ), + child: HomePage(), + ), + ), + ), + ), + AnimatedPositioned( + duration: const Duration(milliseconds: 200), + curve: Curves.fastOutSlowIn, + left: isSideBarOpen ? 220 : 0, + top: 16, + child: MenuBtn( + press: () { + isMenuOpenInput.value = !isMenuOpenInput.value; + + if (_animationController.value == 0) { + _animationController.forward(); + } else { + _animationController.reverse(); + } + + setState( + () { + isSideBarOpen = !isSideBarOpen; + }, + ); + }, + riveOnInit: (artboard) { + final controller = StateMachineController.fromArtboard( + artboard, "State Machine"); + + artboard.addController(controller!); + + isMenuOpenInput = + controller.findInput("isOpen") as SMIBool; + isMenuOpenInput.value = true; + }, + ), + ), + ], + ), + bottomNavigationBar: Transform.translate( + offset: Offset(0, 100 * animation.value), + child: SafeArea( + child: Container( + padding: + const EdgeInsets.only(left: 12, top: 12, right: 12, bottom: 12), + margin: const EdgeInsets.symmetric(horizontal: 24), + decoration: BoxDecoration( + color: backgroundColor2.withOpacity(0.8), + borderRadius: const BorderRadius.all(Radius.circular(24)), + boxShadow: [ + BoxShadow( + color: backgroundColor2.withOpacity(0.3), + offset: const Offset(0, 20), + blurRadius: 20, + ), + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ...List.generate( + bottomNavItems.length, + (index) { + Menu navBar = bottomNavItems[index]; + return BtmNavItem( + navBar: navBar, + press: () { + RiveUtils.chnageSMIBoolState(navBar.rive.status!); + updateSelectedBtmNav(navBar); + }, + riveOnInit: (artboard) { + navBar.rive.status = RiveUtils.getRiveInput(artboard, + stateMachineName: navBar.rive.stateMachineName); + }, + selectedNav: selectedBottonNav, + ); + }, + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/motula_translate_app/lib/screens/home/components/course_card.dart b/motula_translate_app/lib/screens/home/components/course_card.dart new file mode 100644 index 0000000..a459eb4 --- /dev/null +++ b/motula_translate_app/lib/screens/home/components/course_card.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class CourseCard extends StatelessWidget { + const CourseCard({ + Key? key, + required this.title, + this.color = const Color(0xFF7553F6), + this.iconSrc = "assets/icons/ios.svg", + }) : super(key: key); + + final String title, iconSrc; + final Color color; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), + height: 280, + width: 260, + decoration: BoxDecoration( + color: color, + borderRadius: const BorderRadius.all(Radius.circular(30)), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.only(top: 6, right: 8), + child: Column( + children: [ + Text( + title, + style: Theme.of(context).textTheme.titleLarge!.copyWith( + color: Colors.white, fontWeight: FontWeight.w600), + ), + const Padding( + padding: EdgeInsets.only(top: 12, bottom: 8), + child: Text( + "Build and animate an iOS app from scratch", + style: TextStyle( + color: Colors.white38, + ), + ), + ), + const Text( + "61 SECTIONS - 11 HOURS", + style: TextStyle( + color: Colors.white38, + ), + ), + const Spacer(), + Row( + children: List.generate( + 3, + (index) => Transform.translate( + offset: Offset((-10 * index).toDouble(), 0), + child: CircleAvatar( + radius: 20, + backgroundImage: AssetImage( + "assets/avaters/Avatar ${index + 1}.jpg", + ), + ), + ), + ), + ), + ], + ), + ), + ), + SvgPicture.asset(iconSrc), + ], + ), + ); + } +} diff --git a/motula_translate_app/lib/screens/home/components/secondary_course_card.dart b/motula_translate_app/lib/screens/home/components/secondary_course_card.dart new file mode 100644 index 0000000..4751a92 --- /dev/null +++ b/motula_translate_app/lib/screens/home/components/secondary_course_card.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; + +class SecondaryCourseCard extends StatelessWidget { + const SecondaryCourseCard({ + Key? key, + required this.title, + this.iconsSrc = "assets/icons/ios.svg", + this.colorl = const Color(0xFF7553F6), + }) : super(key: key); + + final String title, iconsSrc; + final Color colorl; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 20), + decoration: BoxDecoration( + color: colorl, + borderRadius: const BorderRadius.all(Radius.circular(20))), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: Theme.of(context).textTheme.headlineSmall!.copyWith( + color: Colors.white, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 4), + const Text( + "Watch video - 15 mins", + style: TextStyle( + color: Colors.white60, + fontSize: 16, + ), + ) + ], + ), + ), + const SizedBox( + height: 40, + child: VerticalDivider( + // thickness: 5, + color: Colors.white70, + ), + ), + const SizedBox(width: 8), + SvgPicture.asset(iconsSrc) + ], + ), + ); + } +} diff --git a/motula_translate_app/lib/screens/home/home_screen.dart b/motula_translate_app/lib/screens/home/home_screen.dart new file mode 100644 index 0000000..d3f3fd4 --- /dev/null +++ b/motula_translate_app/lib/screens/home/home_screen.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; + +import '../../model/course.dart'; +import 'components/course_card.dart'; +import 'components/secondary_course_card.dart'; + +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + bottom: false, + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 40), + Padding( + padding: const EdgeInsets.all(20), + child: Text( + "Courses", + style: Theme.of(context).textTheme.headlineMedium!.copyWith( + color: Colors.black, fontWeight: FontWeight.bold), + ), + ), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: courses + .map( + (course) => Padding( + padding: const EdgeInsets.only(left: 20), + child: CourseCard( + title: course.title, + iconSrc: course.iconSrc, + color: course.color, + ), + ), + ) + .toList(), + ), + ), + Padding( + padding: const EdgeInsets.all(20), + child: Text( + "Recent", + style: Theme.of(context).textTheme.headlineSmall!.copyWith( + color: Colors.black, fontWeight: FontWeight.bold), + ), + ), + ...recentCourses + .map((course) => Padding( + padding: const EdgeInsets.only( + left: 20, right: 20, bottom: 20), + child: SecondaryCourseCard( + title: course.title, + iconsSrc: course.iconSrc, + colorl: course.color, + ), + )) + .toList(), + ], + ), + ), + ), + ); + } +} diff --git a/motula_translate_app/lib/screens/onboding/components/animated_btn.dart b/motula_translate_app/lib/screens/onboding/components/animated_btn.dart new file mode 100644 index 0000000..d2263db --- /dev/null +++ b/motula_translate_app/lib/screens/onboding/components/animated_btn.dart @@ -0,0 +1,49 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; + +class AnimatedBtn extends StatelessWidget { + const AnimatedBtn({ + Key? key, + required RiveAnimationController btnAnimationController, + required this.press, + }) : _btnAnimationController = btnAnimationController, + super(key: key); + + final RiveAnimationController _btnAnimationController; + final VoidCallback press; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: press, + child: SizedBox( + height: 64, + width: 236, + child: Stack( + children: [ + RiveAnimation.asset( + "assets/RiveAssets/button.riv", + controllers: [_btnAnimationController], + ), + Positioned.fill( + top: 8, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Icon(CupertinoIcons.arrow_right), + const SizedBox(width: 8), + Text( + "Start the course", + style: Theme.of(context).textTheme.labelLarge, + ) + ], + ), + ) + ], + ), + ), + ); + } +} diff --git a/motula_translate_app/lib/screens/onboding/components/sign_in_dialog.dart b/motula_translate_app/lib/screens/onboding/components/sign_in_dialog.dart new file mode 100644 index 0000000..b23eabd --- /dev/null +++ b/motula_translate_app/lib/screens/onboding/components/sign_in_dialog.dart @@ -0,0 +1,161 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import 'sign_in_form.dart'; + +void showCustomDialog(BuildContext context, {required ValueChanged onValue}) { + showGeneralDialog( + context: context, + barrierLabel: "Barrier", + barrierDismissible: true, + barrierColor: Colors.black.withOpacity(0.5), + transitionDuration: const Duration(milliseconds: 400), + pageBuilder: (_, __, ___) { + return Center( + child: Container( + height: 670, + margin: const EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.symmetric(vertical: 32, horizontal: 24), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.95), + borderRadius: BorderRadius.circular(40), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.3), + offset: const Offset(0, 30), + blurRadius: 60, + ), + const BoxShadow( + color: Colors.black45, + offset: Offset(0, 30), + blurRadius: 60, + ), + ], + ), + child: Scaffold( + // backgroundColor: Colors.transparent, + body: Stack( + clipBehavior: Clip.none, + children: [ + SingleChildScrollView( + child: Column( + children: [ + const Text( + "Sign in", + style: TextStyle( + fontSize: 34, + fontFamily: "Poppins", + fontWeight: FontWeight.w600, + ), + ), + const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Text( + "Access to 240+ hours of content. Learn design and code, by building real apps with Flutter and Swift.", + textAlign: TextAlign.center, + ), + ), + const SignInForm(), + const Row( + children: [ + Expanded( + child: Divider(), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: Text( + "OR", + style: TextStyle( + color: Colors.black26, + fontWeight: FontWeight.w500, + ), + ), + ), + Expanded(child: Divider()), + ], + ), + const Padding( + padding: EdgeInsets.symmetric(vertical: 24), + child: Text( + "Sign up with Email, Apple or Google", + style: TextStyle(color: Colors.black54), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + IconButton( + onPressed: () {}, + padding: EdgeInsets.zero, + icon: SvgPicture.asset( + "assets/icons/email_box.svg", + height: 64, + width: 64, + ), + ), + IconButton( + onPressed: () {}, + padding: EdgeInsets.zero, + icon: SvgPicture.asset( + "assets/icons/apple_box.svg", + height: 64, + width: 64, + ), + ), + IconButton( + onPressed: () {}, + padding: EdgeInsets.zero, + icon: SvgPicture.asset( + "assets/icons/google_box.svg", + height: 64, + width: 64, + ), + ), + ], + ), + ], + ), + ), + const Positioned( + left: 0, + right: 0, + bottom: -48, + child: CircleAvatar( + radius: 16, + backgroundColor: Colors.white, + child: Icon( + Icons.close, + size: 20, + color: Colors.black, + ), + ), + ) + ], + ), + ), + ), + ); + }, + transitionBuilder: (_, anim, __, child) { + Tween tween; + // if (anim.status == AnimationStatus.reverse) { + // tween = Tween(begin: const Offset(0, 1), end: Offset.zero); + // } else { + // tween = Tween(begin: const Offset(0, -1), end: Offset.zero); + // } + + tween = Tween(begin: const Offset(0, -1), end: Offset.zero); + + return SlideTransition( + position: tween.animate( + CurvedAnimation(parent: anim, curve: Curves.easeInOut), + ), + // child: FadeTransition( + // opacity: anim, + // child: child, + // ), + child: child, + ); + }, + ).then(onValue); +} diff --git a/motula_translate_app/lib/screens/onboding/components/sign_in_form.dart b/motula_translate_app/lib/screens/onboding/components/sign_in_form.dart new file mode 100644 index 0000000..1ad2fb6 --- /dev/null +++ b/motula_translate_app/lib/screens/onboding/components/sign_in_form.dart @@ -0,0 +1,225 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:rive/rive.dart'; +import 'package:motula_translate_app/screens/entryPoint/entry_point.dart'; + +class SignInForm extends StatefulWidget { + const SignInForm({ + Key? key, + }) : super(key: key); + + @override + State createState() => _SignInFormState(); +} + +class _SignInFormState extends State { + final GlobalKey _formKey = GlobalKey(); + bool isShowLoading = false; + bool isShowConfetti = false; + late SMITrigger error; + late SMITrigger success; + late SMITrigger reset; + + late SMITrigger confetti; + + void _onCheckRiveInit(Artboard artboard) { + StateMachineController? controller = + StateMachineController.fromArtboard(artboard, 'State Machine 1'); + + artboard.addController(controller!); + error = controller.findInput('Error') as SMITrigger; + success = controller.findInput('Check') as SMITrigger; + reset = controller.findInput('Reset') as SMITrigger; + } + + void _onConfettiRiveInit(Artboard artboard) { + StateMachineController? controller = + StateMachineController.fromArtboard(artboard, "State Machine 1"); + artboard.addController(controller!); + + confetti = controller.findInput("Trigger explosion") as SMITrigger; + } + + void singIn(BuildContext context) { + // confetti.fire(); + setState(() { + isShowConfetti = true; + isShowLoading = true; + }); + Future.delayed( + const Duration(seconds: 1), + () { + if (_formKey.currentState!.validate()) { + success.fire(); + Future.delayed( + const Duration(seconds: 2), + () { + setState(() { + isShowLoading = false; + }); + confetti.fire(); + // Navigate & hide confetti + Future.delayed(const Duration(seconds: 1), () { + // Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const EntryPoint(), + ), + ); + }); + }, + ); + } else { + error.fire(); + Future.delayed( + const Duration(seconds: 2), + () { + setState(() { + isShowLoading = false; + }); + reset.fire(); + }, + ); + } + }, + ); + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Email", + style: TextStyle( + color: Colors.black54, + ), + ), + Padding( + padding: const EdgeInsets.only(top: 8, bottom: 16), + child: TextFormField( + validator: (value) { + if (value!.isEmpty) { + return ""; + } + return null; + }, + keyboardType: TextInputType.emailAddress, + textInputAction: TextInputAction.next, + decoration: InputDecoration( + prefixIcon: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: SvgPicture.asset("assets/icons/email.svg"), + ), + ), + ), + ), + const Text( + "Password", + style: TextStyle( + color: Colors.black54, + ), + ), + Padding( + padding: const EdgeInsets.only(top: 8, bottom: 16), + child: TextFormField( + obscureText: true, + validator: (value) { + if (value!.isEmpty) { + return ""; + } + return null; + }, + decoration: InputDecoration( + prefixIcon: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: SvgPicture.asset("assets/icons/password.svg"), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 8, bottom: 24), + child: ElevatedButton.icon( + onPressed: () { + singIn(context); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFF77D8E), + minimumSize: const Size(double.infinity, 56), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(25), + bottomRight: Radius.circular(25), + bottomLeft: Radius.circular(25), + ), + ), + ), + icon: const Icon( + CupertinoIcons.arrow_right, + color: Color(0xFFFE0037), + ), + label: const Text("Sign In"), + ), + ), + ], + ), + ), + isShowLoading + ? CustomPositioned( + child: RiveAnimation.asset( + 'assets/RiveAssets/check.riv', + fit: BoxFit.cover, + onInit: _onCheckRiveInit, + ), + ) + : const SizedBox(), + isShowConfetti + ? CustomPositioned( + scale: 6, + child: RiveAnimation.asset( + "assets/RiveAssets/confetti.riv", + onInit: _onConfettiRiveInit, + fit: BoxFit.cover, + ), + ) + : const SizedBox(), + ], + ); + } +} + +class CustomPositioned extends StatelessWidget { + const CustomPositioned({super.key, this.scale = 1, required this.child}); + + final double scale; + final Widget child; + + @override + Widget build(BuildContext context) { + return Positioned.fill( + child: Column( + children: [ + const Spacer(), + SizedBox( + height: 100, + width: 100, + child: Transform.scale( + scale: scale, + child: child, + ), + ), + const Spacer(flex: 2), + ], + ), + ); + } +} diff --git a/motula_translate_app/lib/screens/onboding/onboding_screen.dart b/motula_translate_app/lib/screens/onboding/onboding_screen.dart new file mode 100644 index 0000000..1b2d094 --- /dev/null +++ b/motula_translate_app/lib/screens/onboding/onboding_screen.dart @@ -0,0 +1,132 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; + +import 'components/animated_btn.dart'; +import 'components/sign_in_dialog.dart'; + +class OnbodingScreen extends StatefulWidget { + const OnbodingScreen({super.key}); + + @override + State createState() => _OnbodingScreenState(); +} + +class _OnbodingScreenState extends State { + late RiveAnimationController _btnAnimationController; + + bool isShowSignInDialog = false; + + @override + void initState() { + _btnAnimationController = OneShotAnimation( + "active", + autoplay: false, + ); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Stack( + children: [ + Positioned( + width: MediaQuery.of(context).size.width * 1.7, + left: 100, + bottom: 100, + child: Image.asset( + "assets/Backgrounds/Spline.png", + ), + ), + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), + child: const SizedBox(), + ), + ), + const RiveAnimation.asset( + "assets/RiveAssets/shapes.riv", + ), + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 30, sigmaY: 30), + child: const SizedBox(), + ), + ), + AnimatedPositioned( + top: isShowSignInDialog ? -50 : 0, + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + duration: const Duration(milliseconds: 260), + child: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Spacer(), + const SizedBox( + width: 260, + child: Column( + children: [ + Text( + "Learn design & code", + style: TextStyle( + fontSize: 60, + fontWeight: FontWeight.w700, + fontFamily: "Poppins", + height: 1.2, + ), + ), + SizedBox(height: 16), + Text( + "Don’t skip design. Learn design and code, by building real apps with Flutter and Swift. Complete courses about the best tools.", + ), + ], + ), + ), + const Spacer(flex: 2), + AnimatedBtn( + btnAnimationController: _btnAnimationController, + press: () { + _btnAnimationController.isActive = true; + + Future.delayed( + const Duration(milliseconds: 800), + () { + setState(() { + isShowSignInDialog = true; + }); + showCustomDialog( + context, + onValue: (_) {}, + ); + // showCustomDialog( + // context, + // onValue: (_) { + // setState(() { + // isShowSignInDialog = false; + // }); + // }, + // ); + }, + ); + }, + ), + const Padding( + padding: EdgeInsets.symmetric(vertical: 24), + child: Text( + "Purchase includes access to 30+ courses, 240+ premium tutorials, 120+ hours of videos, source files and certificates."), + ) + ], + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/motula_translate_app/lib/utils/rive_utils.dart b/motula_translate_app/lib/utils/rive_utils.dart new file mode 100644 index 0000000..8d17758 --- /dev/null +++ b/motula_translate_app/lib/utils/rive_utils.dart @@ -0,0 +1,23 @@ +import 'package:rive/rive.dart'; + +class RiveUtils { + static SMIBool getRiveInput(Artboard artboard, + {required String stateMachineName}) { + StateMachineController? controller = + StateMachineController.fromArtboard(artboard, stateMachineName); + + artboard.addController(controller!); + + return controller.findInput("active") as SMIBool; + } + + static void chnageSMIBoolState(SMIBool input) { + input.change(true); + Future.delayed( + const Duration(seconds: 1), + () { + input.change(false); + }, + ); + } +} diff --git a/motula_translate_app/macos/Flutter/GeneratedPluginRegistrant.swift b/motula_translate_app/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..93cc9c1 100644 --- a/motula_translate_app/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/motula_translate_app/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,8 @@ import FlutterMacOS import Foundation +import rive_common func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin")) } diff --git a/motula_translate_app/pubspec.lock b/motula_translate_app/pubspec.lock index f5b0af9..a50a23f 100644 --- a/motula_translate_app/pubspec.lock +++ b/motula_translate_app/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" async: dependency: transitive description: @@ -57,6 +65,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://pub.dev" + source: hosted + version: "2.1.2" flutter: dependency: "direct main" description: flutter @@ -66,15 +82,52 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "2.0.3" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" + url: "https://pub.dev" + source: hosted + version: "2.0.10+1" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + http: + dependency: "direct main" + description: + name: http + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" leak_tracker: dependency: transitive description: @@ -103,10 +156,10 @@ packages: dependency: transitive description: name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "2.1.1" matcher: dependency: transitive description: @@ -139,6 +192,46 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + rive: + dependency: "direct main" + description: + name: rive + sha256: ae75a6e9cfbf146630bfb1feba97ee582d935508be6b362e4bd197b9c55a6dd3 + url: "https://pub.dev" + source: hosted + version: "0.12.4" + rive_common: + dependency: transitive + description: + name: rive_common + sha256: f4e20d0a99c5040c85624a3eb2b0b6b19e614d93a693c3bb25cf6e7bb2d3d6d3 + url: "https://pub.dev" + source: hosted + version: "0.2.8" sky_engine: dependency: transitive description: flutter @@ -192,6 +285,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" vector_math: dependency: transitive description: @@ -208,5 +333,22 @@ packages: url: "https://pub.dev" source: hosted version: "13.0.0" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" sdks: dart: ">=3.3.0 <4.0.0" + flutter: ">=3.7.0-0" diff --git a/motula_translate_app/pubspec.yaml b/motula_translate_app/pubspec.yaml index be94a74..4e81ea6 100644 --- a/motula_translate_app/pubspec.yaml +++ b/motula_translate_app/pubspec.yaml @@ -2,7 +2,7 @@ name: motula_translate_app description: "A new Flutter project." # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +publish_to: "none" # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -19,7 +19,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=3.3.0 <4.0.0' + sdk: ">=3.2.0 <4.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -31,10 +31,12 @@ dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.6 + cupertino_icons: ^1.0.2 + rive: ^0.12.4 + flutter_svg: ^2.0.9 + http: ^1.2.1 dev_dependencies: flutter_test: @@ -45,23 +47,24 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^3.0.0 + flutter_lints: ^2.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter packages. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + assets: + - assets/avaters/ + - assets/Backgrounds/ + - assets/icons/ + - assets/RiveAssets/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware @@ -74,17 +77,16 @@ 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 - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 + fonts: + - family: Intel + fonts: + - asset: assets/Fonts/Inter-Regular.ttf + - asset: assets/Fonts/Inter-SemiBold.ttf + weight: 600 + - family: Poppins + fonts: + - asset: assets/Fonts/Poppins-Bold.ttf + weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages diff --git a/motula_translate_app/windows/flutter/generated_plugin_registrant.cc b/motula_translate_app/windows/flutter/generated_plugin_registrant.cc index 8b6d468..829b2da 100644 --- a/motula_translate_app/windows/flutter/generated_plugin_registrant.cc +++ b/motula_translate_app/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + RivePluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("RivePlugin")); } diff --git a/motula_translate_app/windows/flutter/generated_plugins.cmake b/motula_translate_app/windows/flutter/generated_plugins.cmake index b93c4c3..ea49fcc 100644 --- a/motula_translate_app/windows/flutter/generated_plugins.cmake +++ b/motula_translate_app/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + rive_common ) list(APPEND FLUTTER_FFI_PLUGIN_LIST