39 changed files with 727 additions and 66 deletions
-
BINassets/fonts/Baloo2-Bold.ttf
-
BINassets/fonts/Baloo2-ExtraBold.ttf
-
BINassets/fonts/Baloo2-Medium.ttf
-
BINassets/fonts/Baloo2-SemiBold.ttf
-
0assets/fonts/DinoKids-Regular.ttf
-
BINassets/fonts/Marhey-Light.ttf
-
BINassets/fonts/Marhey-Medium.ttf
-
BINassets/fonts/Marhey-Regular.ttf
-
BINassets/images/intro_1.jpg
-
BINassets/images/intro_2.jpg
-
BINassets/images/intro_3.jpg
-
BINassets/images/intro_4.jpg
-
BINassets/images/intro_5.jpg
-
10lib/common_ui/resources/my_assets.dart
-
137lib/common_ui/resources/my_text_style.dart
-
18lib/common_ui/theme/my_theme.dart
-
2lib/core/routers/my_routes.dart
-
14lib/core/utils/my_device.dart
-
7lib/core/utils/screen_size.dart
-
18lib/core/utils/set_platform_size.dart
-
16lib/core/widgets/about_us_dialog/about_us_dialog.dart
-
6lib/core/widgets/about_us_dialog/styles/background.dart
-
67lib/core/widgets/animations/slide_up_fade.dart
-
8lib/core/widgets/hadith_dialog/hadith_dialog.dart
-
29lib/features/intro/presentation/bloc/intro_bloc.dart
-
2lib/features/intro/presentation/bloc/intro_event.dart
-
8lib/features/intro/presentation/bloc/intro_state.dart
-
55lib/features/intro/presentation/ui/intro_page.dart
-
54lib/features/intro/presentation/ui/screens/intro_1_screen.dart
-
37lib/features/intro/presentation/ui/screens/intro_2_screen.dart
-
37lib/features/intro/presentation/ui/screens/intro_3_screen.dart
-
36lib/features/intro/presentation/ui/screens/intro_4_screen.dart
-
34lib/features/intro/presentation/ui/screens/intro_5_screen.dart
-
91lib/features/intro/presentation/ui/widgets/bubble_chat_widget.dart
-
9lib/l10n/app_en.arb
-
42lib/l10n/app_localizations.dart
-
24lib/l10n/app_localizations_en.dart
-
1lib/main.dart
-
31pubspec.yaml
|
After Width: 819 | Height: 1229 | Size: 147 KiB |
|
After Width: 819 | Height: 1229 | Size: 139 KiB |
|
After Width: 819 | Height: 1229 | Size: 134 KiB |
|
After Width: 819 | Height: 1229 | Size: 141 KiB |
|
After Width: 819 | Height: 1229 | Size: 179 KiB |
@ -1,24 +1,10 @@ |
|||||
import 'package:flutter/material.dart'; |
import 'package:flutter/material.dart'; |
||||
import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart'; |
|
||||
|
|
||||
enum ColorsName { primaryColor, backgroundDialog } |
|
||||
|
|
||||
class MyTheme { |
class MyTheme { |
||||
static const MyTheme _i = MyTheme._internal(); |
static const MyTheme _i = MyTheme._internal(); |
||||
const MyTheme._internal(); |
const MyTheme._internal(); |
||||
factory MyTheme() => _i; |
factory MyTheme() => _i; |
||||
|
|
||||
static final ThemeData light = ThemeData(brightness: Brightness.dark); |
|
||||
|
|
||||
static final ThemeData dark = ThemeData(brightness: Brightness.light); |
|
||||
|
|
||||
static Map<ColorsName, Color> get lightColors => { |
|
||||
ColorsName.primaryColor: MyColors.white, |
|
||||
ColorsName.backgroundDialog: MyColors.purple, |
|
||||
}; |
|
||||
|
|
||||
static Map<ColorsName, Color> get darkColors => { |
|
||||
ColorsName.primaryColor: MyColors.black, |
|
||||
ColorsName.backgroundDialog: MyColors.purple, |
|
||||
}; |
|
||||
|
static final ThemeData light = ThemeData(brightness: Brightness.light); |
||||
|
static final ThemeData dark = ThemeData(brightness: Brightness.dark); |
||||
} |
} |
||||
@ -1,6 +1,13 @@ |
|||||
import 'package:flutter/material.dart'; |
import 'package:flutter/material.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; |
||||
|
|
||||
extension ScreenSize on BuildContext { |
extension ScreenSize on BuildContext { |
||||
double get widthScreen => MediaQuery.sizeOf(this).width; |
double get widthScreen => MediaQuery.sizeOf(this).width; |
||||
double get heightScreen => MediaQuery.sizeOf(this).height; |
double get heightScreen => MediaQuery.sizeOf(this).height; |
||||
} |
} |
||||
|
|
||||
|
|
||||
|
extension AdaptiveSize on double { |
||||
|
double get w => ContextProvider.context.widthScreen * this; |
||||
|
double get h => ContextProvider.context.heightScreen * this; |
||||
|
} |
||||
@ -0,0 +1,67 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
|
||||
|
class SlideUpFade extends StatefulWidget { |
||||
|
const SlideUpFade({ |
||||
|
super.key, |
||||
|
required this.child, |
||||
|
this.delay = Duration.zero, |
||||
|
}); |
||||
|
|
||||
|
final Widget child; |
||||
|
final Duration delay; |
||||
|
|
||||
|
@override |
||||
|
State<SlideUpFade> createState() => _SlideUpFadeState(); |
||||
|
} |
||||
|
|
||||
|
class _SlideUpFadeState extends State<SlideUpFade> |
||||
|
with SingleTickerProviderStateMixin { |
||||
|
late AnimationController _controller; |
||||
|
late Animation<double> _fadeAnim; |
||||
|
late Animation<Offset> _slideAnim; |
||||
|
|
||||
|
@override |
||||
|
void initState() { |
||||
|
super.initState(); |
||||
|
_controller = AnimationController( |
||||
|
vsync: this, |
||||
|
duration: Duration(milliseconds: 500), |
||||
|
reverseDuration: Duration(milliseconds: 500), |
||||
|
); |
||||
|
|
||||
|
_fadeAnim = Tween<double>( |
||||
|
begin: 0, |
||||
|
end: 1, |
||||
|
).animate(CurvedAnimation(parent: _controller, curve: Curves.easeIn)); |
||||
|
|
||||
|
_slideAnim = Tween<Offset>( |
||||
|
begin: Offset(0, 0.1), |
||||
|
end: Offset.zero, |
||||
|
).animate(CurvedAnimation(parent: _controller, curve: Curves.easeIn)); |
||||
|
startAnim(); |
||||
|
} |
||||
|
|
||||
|
Future<void> startAnim() async { |
||||
|
await Future.delayed(widget.delay, () { |
||||
|
_controller.forward(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
void dispose() { |
||||
|
_controller.dispose(); |
||||
|
super.dispose(); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return AnimatedBuilder( |
||||
|
animation: _controller, |
||||
|
child: widget.child, |
||||
|
builder: (context, child) => FadeTransition( |
||||
|
opacity: _fadeAnim, |
||||
|
child: SlideTransition(position: _slideAnim, child: child), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -1,23 +1,48 @@ |
|||||
import 'dart:async'; |
import 'dart:async'; |
||||
|
|
||||
import 'package:bloc/bloc.dart'; |
import 'package:bloc/bloc.dart'; |
||||
|
import 'package:flutter/cupertino.dart'; |
||||
|
import 'package:go_router/go_router.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; |
||||
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_event.dart'; |
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_event.dart'; |
||||
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_state.dart'; |
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_state.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/screens/intro_1_screen.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/screens/intro_2_screen.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/screens/intro_3_screen.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/screens/intro_4_screen.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/screens/intro_5_screen.dart'; |
||||
|
|
||||
class IntroBloc extends Bloc<IntroEvent, IntroState> { |
class IntroBloc extends Bloc<IntroEvent, IntroState> { |
||||
/// ------------constructor------------ |
/// ------------constructor------------ |
||||
IntroBloc() : super(const IntroState()){ |
IntroBloc() : super(const IntroState()){ |
||||
on<GetIntroEvent>(_getIntroEvent); |
|
||||
|
on<ChangeIntroEvent>(_changeIntroEvent); |
||||
} |
} |
||||
|
|
||||
/// ------------UseCases------------ |
/// ------------UseCases------------ |
||||
|
|
||||
/// ------------Variables------------ |
/// ------------Variables------------ |
||||
|
final List<Widget> intros = [ |
||||
|
Intro1Screen(key: Key('0')), |
||||
|
Intro2Screen(key: Key('1')), |
||||
|
Intro3Screen(key: Key('2')), |
||||
|
Intro4Screen(key: Key('3')), |
||||
|
Intro5Screen(key: Key('4')), |
||||
|
]; |
||||
|
|
||||
/// ------------Controllers------------ |
/// ------------Controllers------------ |
||||
|
|
||||
/// ------------Functions------------ |
/// ------------Functions------------ |
||||
|
void goToLevelPage(){ |
||||
|
ContextProvider.context.go(Routes.levelPage); |
||||
|
} |
||||
|
|
||||
/// ------------Api Calls------------ |
/// ------------Api Calls------------ |
||||
FutureOr<void> _getIntroEvent(event, emit) async {} |
|
||||
|
FutureOr<void> _changeIntroEvent(ChangeIntroEvent event, Emitter emit) async { |
||||
|
if (state.currentIntro < intros.length - 1) { |
||||
|
emit(state.copyWith(currentIntro: state.currentIntro + 1)); |
||||
|
} else { |
||||
|
goToLevelPage(); |
||||
|
} |
||||
|
} |
||||
} |
} |
||||
@ -1,10 +1,63 @@ |
|||||
import 'package:flutter/material.dart'; |
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_bloc/flutter_bloc.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_bloc.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_event.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_state.dart'; |
||||
|
|
||||
class IntroPage extends StatelessWidget { |
class IntroPage extends StatelessWidget { |
||||
const IntroPage({super.key}); |
const IntroPage({super.key}); |
||||
|
|
||||
@override |
@override |
||||
Widget build(BuildContext context) { |
Widget build(BuildContext context) { |
||||
return const Scaffold(); |
|
||||
|
return Scaffold( |
||||
|
body: SizedBox.expand( |
||||
|
child: GestureDetector( |
||||
|
onTap: () => context.read<IntroBloc>().add(ChangeIntroEvent()), |
||||
|
child: Stack( |
||||
|
children: [ |
||||
|
_mainScreen(), |
||||
|
_skipButton(context), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
BlocBuilder<IntroBloc, IntroState> _mainScreen() { |
||||
|
return BlocBuilder<IntroBloc, IntroState>( |
||||
|
builder: (context, state) => AnimatedSwitcher( |
||||
|
duration: Duration(milliseconds: 200), |
||||
|
reverseDuration: Duration(milliseconds: 200), |
||||
|
switchInCurve: Curves.linear, |
||||
|
switchOutCurve: Curves.linear, |
||||
|
child: context.read<IntroBloc>().intros[state.currentIntro], |
||||
|
transitionBuilder: (child, animation) => |
||||
|
FadeTransition(opacity: animation, child: child), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
PositionedDirectional _skipButton(BuildContext context) { |
||||
|
return PositionedDirectional( |
||||
|
start: MySpaces.s30, |
||||
|
bottom: MySpaces.s16, |
||||
|
child: TextButton( |
||||
|
onPressed: () => context.read<IntroBloc>().goToLevelPage(), |
||||
|
style: TextButton.styleFrom( |
||||
|
foregroundColor: MyColors.white.withValues(alpha: 0.7), |
||||
|
), |
||||
|
child: Text( |
||||
|
context.translate.skip, |
||||
|
style: MYTextStyle.button2.copyWith( |
||||
|
color: MyColors.white.withValues(alpha: 0.7), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/widgets/animations/slide_up_fade.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/widgets/bubble_chat_widget.dart'; |
||||
|
|
||||
|
class Intro1Screen extends StatelessWidget { |
||||
|
const Intro1Screen({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Stack( |
||||
|
alignment: Alignment.center, |
||||
|
children: [ |
||||
|
Positioned.fill( |
||||
|
child: MyImage(image: MyAssets.intro_1, fit: BoxFit.cover), |
||||
|
), |
||||
|
PositionedDirectional( |
||||
|
end: setSize<double>( |
||||
|
context: context, |
||||
|
mobile: MySpaces.s10, |
||||
|
tablet: 0.15.w, |
||||
|
), |
||||
|
top: setSize<double>( |
||||
|
context: context, |
||||
|
mobile: 0.15.h, |
||||
|
tablet: 0.25.h, |
||||
|
), |
||||
|
width: 290, |
||||
|
child: SlideUpFade( |
||||
|
delay: Duration(milliseconds: 300), |
||||
|
child: BubbleChatWidget( |
||||
|
text: context.translate.intro_1_1, |
||||
|
flip: true, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
PositionedDirectional( |
||||
|
start: setSize(context: context, mobile: MySpaces.s30, tablet: 0.2.w), |
||||
|
top: setSize(context: context, mobile: 0.3.h, tablet: 0.35.h), |
||||
|
width: 250, |
||||
|
child: SlideUpFade( |
||||
|
delay: Duration(milliseconds: 800), |
||||
|
child: BubbleChatWidget(text: context.translate.intro_1_2), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/widgets/animations/slide_up_fade.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/widgets/bubble_chat_widget.dart'; |
||||
|
|
||||
|
class Intro2Screen extends StatelessWidget { |
||||
|
const Intro2Screen({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Stack( |
||||
|
alignment: Alignment.center, |
||||
|
children: [ |
||||
|
Positioned.fill( |
||||
|
child: Transform.flip( |
||||
|
flipX: true, |
||||
|
child: MyImage(image: MyAssets.intro_2, fit: BoxFit.cover), |
||||
|
), |
||||
|
), |
||||
|
PositionedDirectional( |
||||
|
end: setSize(context: context, mobile: MySpaces.s40, tablet: 0.3.w), |
||||
|
top: setSize(context: context, mobile: 0.17.h, tablet: 0.23.h), |
||||
|
width: 250, |
||||
|
child: SlideUpFade( |
||||
|
delay: Duration(milliseconds: 300), |
||||
|
child: BubbleChatWidget(text: context.translate.intro_2), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/widgets/animations/slide_up_fade.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/widgets/bubble_chat_widget.dart'; |
||||
|
|
||||
|
class Intro3Screen extends StatelessWidget { |
||||
|
const Intro3Screen({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Stack( |
||||
|
alignment: Alignment.center, |
||||
|
children: [ |
||||
|
Positioned.fill( |
||||
|
child: MyImage(image: MyAssets.intro_3, fit: BoxFit.cover), |
||||
|
), |
||||
|
PositionedDirectional( |
||||
|
start: setSize(context: context, mobile: MySpaces.s30), |
||||
|
top: setSize(context: context, mobile: 180, tablet: 0.25.h), |
||||
|
width: 270, |
||||
|
child: SlideUpFade( |
||||
|
delay: Duration(milliseconds: 300), |
||||
|
child: BubbleChatWidget( |
||||
|
text: context.translate.intro_3, |
||||
|
flip: true, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/widgets/animations/slide_up_fade.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/widgets/bubble_chat_widget.dart'; |
||||
|
|
||||
|
class Intro4Screen extends StatelessWidget { |
||||
|
const Intro4Screen({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Stack( |
||||
|
alignment: Alignment.center, |
||||
|
children: [ |
||||
|
Positioned.fill( |
||||
|
child: MyImage(image: MyAssets.intro_4, fit: BoxFit.cover), |
||||
|
), |
||||
|
PositionedDirectional( |
||||
|
start: setSize(context: context, mobile: MySpaces.s10, tablet: 0.2.w), |
||||
|
bottom: setSize(context: context, mobile: 0.4.h, tablet: 0.4.h), |
||||
|
width: 237, |
||||
|
child: SlideUpFade( |
||||
|
delay: Duration(milliseconds: 300), |
||||
|
child: BubbleChatWidget( |
||||
|
text: context.translate.intro_4, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/widgets/animations/slide_up_fade.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/widgets/bubble_chat_widget.dart'; |
||||
|
|
||||
|
class Intro5Screen extends StatelessWidget { |
||||
|
const Intro5Screen({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Stack( |
||||
|
alignment: Alignment.center, |
||||
|
children: [ |
||||
|
Positioned.fill( |
||||
|
child: MyImage(image: MyAssets.intro_5, fit: BoxFit.cover), |
||||
|
), |
||||
|
PositionedDirectional( |
||||
|
top: setSize(context: context, mobile: 0.37.h, tablet: 0.42.h), |
||||
|
width: 200, |
||||
|
child: SlideUpFade( |
||||
|
delay: Duration(milliseconds: 300), |
||||
|
child: BubbleChatWidget( |
||||
|
text: context.translate.intro_5, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,91 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; |
||||
|
|
||||
|
class BubbleChatWidget extends StatelessWidget { |
||||
|
const BubbleChatWidget({ |
||||
|
super.key, |
||||
|
this.text, |
||||
|
this.width, |
||||
|
this.flip = false, |
||||
|
}); |
||||
|
|
||||
|
final String? text; |
||||
|
final double? width; |
||||
|
final bool flip; |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return ClipPath( |
||||
|
clipper: _ShapeClipper(flip: flip), |
||||
|
child: Container( |
||||
|
width: width, |
||||
|
padding: EdgeInsets.only( |
||||
|
left: MySpaces.s18, |
||||
|
right: MySpaces.s18, |
||||
|
top: MySpaces.s16, |
||||
|
bottom: MySpaces.s28, |
||||
|
), |
||||
|
decoration: BoxDecoration( |
||||
|
color: Color(0XFFF5E8D7).withValues(alpha: 0.5), |
||||
|
borderRadius: BorderRadius.all(Radius.circular(20)), |
||||
|
border: Border.all( |
||||
|
width: 1, |
||||
|
color: MyColors.white.withValues(alpha: 0.5), |
||||
|
), |
||||
|
), |
||||
|
child: Text( |
||||
|
text ?? '', |
||||
|
style: MYTextStyle.titr3.copyWith( |
||||
|
color: MyColors.black, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
class _ShapeClipper extends CustomClipper<Path> { |
||||
|
final bool flip; |
||||
|
|
||||
|
_ShapeClipper({this.flip = false}); // Add constructor |
||||
|
|
||||
|
@override |
||||
|
Path getClip(Size size) { |
||||
|
var path = Path(); |
||||
|
double w = size.width; |
||||
|
double h = size.height; |
||||
|
|
||||
|
// The drawing logic remains exactly the same |
||||
|
path.moveTo(w * 0.92, 0); |
||||
|
path.cubicTo(w * 0.96, 0, w, h * 0.05, w, h * 0.12); |
||||
|
path.lineTo(w, h * 0.70); |
||||
|
path.cubicTo(w, h * 0.78, w * 0.96, h * 0.83, w * 0.92, h * 0.83); |
||||
|
path.lineTo(w * 0.35, h * 0.83); |
||||
|
path.lineTo(w * 0.285, h); |
||||
|
path.lineTo(w * 0.20, h * 0.83); |
||||
|
path.lineTo(w * 0.08, h * 0.83); |
||||
|
path.cubicTo(w * 0.03, h * 0.83, 0, h * 0.78, 0, h * 0.70); |
||||
|
path.lineTo(0, h * 0.12); |
||||
|
path.cubicTo(0, h * 0.05, w * 0.03, 0, w * 0.08, 0); |
||||
|
path.close(); |
||||
|
|
||||
|
// If flip is true, transform the path horizontally |
||||
|
if (flip) { |
||||
|
final flipMatrix = Matrix4.identity() |
||||
|
..translateByDouble(w, 0.0, 0.0, 1.0) |
||||
|
..scaleByDouble(-1.0, 1.0, 1.0, 1.0); |
||||
|
return path.transform(flipMatrix.storage); |
||||
|
} |
||||
|
|
||||
|
return path; |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
bool shouldReclip(covariant _ShapeClipper oldClipper) { |
||||
|
return oldClipper.flip != flip; // Reclip if the flip state changes |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue