feat:onboarding page ui done
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'package:food_delivery_client/core/theme/app_theme_colors.dart';
|
||||
import 'package:food_delivery_client/core/theme/app_theme_textstyles.dart';
|
||||
import 'package:food_delivery_client/core/theme/theme_icons.dart';
|
||||
|
||||
@@ -18,4 +19,6 @@ extension BuildContextExtensions on BuildContext {
|
||||
|
||||
AppThemeTextStyles get appThemeTextStyles =>
|
||||
theme.extension<AppThemeTextStyles>()!;
|
||||
|
||||
AppThemeColors get appThemeColors => theme.extension<AppThemeColors>()!;
|
||||
}
|
||||
|
||||
@@ -135,6 +135,42 @@ abstract class AppLocalizations {
|
||||
/// In en, this message translates to:
|
||||
/// **'An unexpected error occurred. Please try again.'**
|
||||
String get unexpected_error;
|
||||
|
||||
/// No description provided for @onboarding_title_1.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Bringing the best flavors food in the world'**
|
||||
String get onboarding_title_1;
|
||||
|
||||
/// No description provided for @onboarding_subtitle_1.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Discover your favorite meals and get them delivered fast wherever you are.'**
|
||||
String get onboarding_subtitle_1;
|
||||
|
||||
/// No description provided for @onboarding_button_next.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Next'**
|
||||
String get onboarding_button_next;
|
||||
|
||||
/// No description provided for @onboarding_title_2.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'A place for extraordinary people in the world'**
|
||||
String get onboarding_title_2;
|
||||
|
||||
/// No description provided for @onboarding_subtitle_2.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Discover your favorite meals and get them delivered fast wherever you are.'**
|
||||
String get onboarding_subtitle_2;
|
||||
|
||||
/// No description provided for @onboarding_button_get_started.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Get Started'**
|
||||
String get onboarding_button_get_started;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
||||
@@ -27,4 +27,26 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get unexpected_error =>
|
||||
'An unexpected error occurred. Please try again.';
|
||||
|
||||
@override
|
||||
String get onboarding_title_1 =>
|
||||
'Bringing the best flavors food in the world';
|
||||
|
||||
@override
|
||||
String get onboarding_subtitle_1 =>
|
||||
'Discover your favorite meals and get them delivered fast wherever you are.';
|
||||
|
||||
@override
|
||||
String get onboarding_button_next => 'Next';
|
||||
|
||||
@override
|
||||
String get onboarding_title_2 =>
|
||||
'A place for extraordinary people in the world';
|
||||
|
||||
@override
|
||||
String get onboarding_subtitle_2 =>
|
||||
'Discover your favorite meals and get them delivered fast wherever you are.';
|
||||
|
||||
@override
|
||||
String get onboarding_button_get_started => 'Get Started';
|
||||
}
|
||||
|
||||
@@ -27,4 +27,24 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
@override
|
||||
String get unexpected_error =>
|
||||
'Произошла непредвиденная ошибка. Пожалуйста, попробуйте снова.';
|
||||
|
||||
@override
|
||||
String get onboarding_title_1 => 'Доставка лучших вкусов мира';
|
||||
|
||||
@override
|
||||
String get onboarding_subtitle_1 =>
|
||||
'Находите свои любимые блюда и получайте их быстро, где бы вы ни находились.';
|
||||
|
||||
@override
|
||||
String get onboarding_button_next => 'Далее';
|
||||
|
||||
@override
|
||||
String get onboarding_title_2 => 'Место для выдающихся людей по всему миру';
|
||||
|
||||
@override
|
||||
String get onboarding_subtitle_2 =>
|
||||
'Находите свои любимые блюда и получайте их быстро, где бы вы ни находились.';
|
||||
|
||||
@override
|
||||
String get onboarding_button_get_started => 'Начать';
|
||||
}
|
||||
|
||||
@@ -27,4 +27,24 @@ class AppLocalizationsUz extends AppLocalizations {
|
||||
@override
|
||||
String get unexpected_error =>
|
||||
'Kutilmagan xatolik yuz berdi. Iltimos, qayta urinib ko‘ring.';
|
||||
|
||||
@override
|
||||
String get onboarding_title_1 => 'Dunyoning eng mazali taomlari siz uchun';
|
||||
|
||||
@override
|
||||
String get onboarding_subtitle_1 =>
|
||||
'Sevimli taomlaringizni toping va ularni tezda yetkazib oling, qaerda bo‘lishingizdan qat’i nazar.';
|
||||
|
||||
@override
|
||||
String get onboarding_button_next => 'Keyingi';
|
||||
|
||||
@override
|
||||
String get onboarding_title_2 => 'Butun dunyodagi ajoyib insonlar uchun joy';
|
||||
|
||||
@override
|
||||
String get onboarding_subtitle_2 =>
|
||||
'Sevimli taomlaringizni toping va ularni tezda yetkazib oling, qaerda bo‘lishingizdan qat’i nazar.';
|
||||
|
||||
@override
|
||||
String get onboarding_button_get_started => 'Boshlash';
|
||||
}
|
||||
|
||||
@@ -48,4 +48,9 @@ abstract class AppColors {
|
||||
static const Color c9EA5B7 = Color(0xFF9EA5B7);
|
||||
static const Color c479B36 = Color(0xFF479B36);
|
||||
static const Color cFFAB40 = Color(0xFFFFAB40);
|
||||
static const Color cD6D4D4 = Color(0xFFD6D4D4);
|
||||
static const Color c1A202C = Color(0xFF1A202C);
|
||||
static const Color c524242 = Color(0xFF524242 );
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
abstract class AppIcons {
|
||||
static const String baseUrl = "assets/icons/common";
|
||||
static const String icLogo = "$baseUrl/ic_logo.svg";
|
||||
static const String icOnBoarding1 = "$baseUrl/ic_onboarding1.svg";
|
||||
static const String icOnBoarding2 = "$baseUrl/ic_onboarding2.svg";
|
||||
static const String icOnBoarding3 = "$baseUrl/ic_onboarding3.svg";
|
||||
}
|
||||
|
||||
abstract class AppLightSvgs {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:food_delivery_client/core/theme/app_theme_colors.dart';
|
||||
import 'package:food_delivery_client/core/theme/app_theme_textstyles.dart';
|
||||
import 'package:food_delivery_client/core/theme/theme_icons.dart';
|
||||
|
||||
@@ -6,7 +7,11 @@ import '../../food_delivery_client.dart';
|
||||
abstract class AppTheme {
|
||||
static ThemeData get lightTheme => ThemeData.light().copyWith(
|
||||
brightness: Brightness.light,
|
||||
extensions: [AppThemeIcons.light, AppThemeTextStyles.light],
|
||||
extensions: [
|
||||
AppThemeIcons.light,
|
||||
AppThemeTextStyles.light,
|
||||
AppThemeColors.light,
|
||||
],
|
||||
|
||||
// colorScheme: ColorScheme(
|
||||
// brightness: Brightness.light,
|
||||
@@ -93,7 +98,11 @@ abstract class AppTheme {
|
||||
|
||||
static ThemeData get darkTheme => ThemeData.light().copyWith(
|
||||
brightness: Brightness.dark,
|
||||
extensions: [AppThemeIcons.dark, AppThemeTextStyles.dark],
|
||||
extensions: [
|
||||
AppThemeIcons.dark,
|
||||
AppThemeTextStyles.dark,
|
||||
AppThemeColors.dark,
|
||||
],
|
||||
|
||||
// colorScheme: ColorScheme(
|
||||
// brightness: Brightness.light,
|
||||
|
||||
39
lib/core/theme/app_theme_colors.dart
Normal file
39
lib/core/theme/app_theme_colors.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||
|
||||
class AppThemeColors extends ThemeExtension<AppThemeColors> {
|
||||
final Color onBoardingColor;
|
||||
final Color boxShadow;
|
||||
|
||||
AppThemeColors({required this.onBoardingColor, required this.boxShadow});
|
||||
|
||||
static AppThemeColors light = AppThemeColors(
|
||||
onBoardingColor: AppColors.cFFFFFF,
|
||||
boxShadow: AppColors.cD6D4D4,
|
||||
);
|
||||
|
||||
static AppThemeColors dark = AppThemeColors(
|
||||
onBoardingColor: AppColors.c131720,
|
||||
boxShadow: AppColors.c524242,
|
||||
);
|
||||
|
||||
@override
|
||||
ThemeExtension<AppThemeColors> copyWith({
|
||||
Color? onBoardingColor,
|
||||
Color? boxShadow,
|
||||
}) {
|
||||
return AppThemeColors(
|
||||
onBoardingColor: onBoardingColor ?? this.onBoardingColor,
|
||||
boxShadow: boxShadow ?? this.boxShadow,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ThemeExtension<AppThemeColors> lerp(
|
||||
covariant ThemeExtension<AppThemeColors>? other,
|
||||
double t,
|
||||
) {
|
||||
if (other is! AppThemeColors) return this;
|
||||
return t < 0.5 ? this : other;
|
||||
}
|
||||
}
|
||||
@@ -57,8 +57,11 @@ class AppThemeTextStyles extends ThemeExtension<AppThemeTextStyles> {
|
||||
),
|
||||
size24SemiBold: TextStyle(
|
||||
fontSize: 24,
|
||||
height: 1.3,
|
||||
letterSpacing: -.48,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: _fontSemiBold,
|
||||
color: AppColors.c1A202C,
|
||||
),
|
||||
size14Bold: TextStyle(
|
||||
fontSize: 14,
|
||||
@@ -96,8 +99,11 @@ class AppThemeTextStyles extends ThemeExtension<AppThemeTextStyles> {
|
||||
),
|
||||
size24SemiBold: TextStyle(
|
||||
fontSize: 24,
|
||||
height: 1.3,
|
||||
letterSpacing: -.48,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: _fontSemiBold,
|
||||
color: AppColors.cFFFFFF,
|
||||
),
|
||||
size14Bold: TextStyle(
|
||||
fontSize: 14,
|
||||
|
||||
@@ -42,8 +42,8 @@ class AppButton extends StatelessWidget {
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor ?? AppColors.c000000,
|
||||
borderRadius: BorderRadius.circular(borderRadius ?? 0),
|
||||
color: backgroundColor ?? AppColors.cFF6F00,
|
||||
borderRadius: BorderRadius.circular(borderRadius ?? 12),
|
||||
),
|
||||
child: isLoading
|
||||
? Center(
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:food_delivery_client/core/core.dart';
|
||||
|
||||
import '../../../../core/theme/app_colors.dart';
|
||||
|
||||
/// A simple animated dot indicator that uses AnimatedContainer.
|
||||
/// Update [activeIndex] to animate which dot is active.
|
||||
class AnimatedDotsIndicator extends StatelessWidget {
|
||||
final int count;
|
||||
final int activeIndex;
|
||||
final double dotSize;
|
||||
final double activeDotWidth;
|
||||
final double spacing;
|
||||
final Duration duration;
|
||||
final Curve curve;
|
||||
final Color activeColor;
|
||||
final Color inactiveColor;
|
||||
final BorderRadius borderRadius;
|
||||
|
||||
const AnimatedDotsIndicator({
|
||||
Key? key,
|
||||
required this.count,
|
||||
required this.activeIndex,
|
||||
this.dotSize = 4,
|
||||
this.activeDotWidth = 32.0,
|
||||
this.spacing =4,
|
||||
this.duration = const Duration(milliseconds: 300),
|
||||
this.curve = Curves.easeInOut,
|
||||
this.activeColor = AppColors.cFF6F00,
|
||||
this.inactiveColor = AppColors.cFFEDCC,
|
||||
this.borderRadius = const BorderRadius.all(Radius.circular(12)),
|
||||
}) : assert(count >= 0),
|
||||
assert(activeIndex >= 0),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(count, (index) {
|
||||
final bool isActive = index == activeIndex;
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(right: index == count - 1 ? 0 : spacing),
|
||||
child: AnimatedContainer(
|
||||
duration: duration,
|
||||
curve: curve,
|
||||
width: activeDotWidth,
|
||||
height: dotSize,
|
||||
decoration: BoxDecoration(
|
||||
color: isActive ? activeColor : inactiveColor,
|
||||
borderRadius: borderRadius,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'splash_event.dart';
|
||||
|
||||
|
||||
@@ -1,10 +1,91 @@
|
||||
import 'package:food_delivery_client/feature/common/presentation/widgets/w_animated_dots_indicator.dart';
|
||||
import 'package:food_delivery_client/feature/onboarding/presentation/pages/onboarding_page/widgets/w_onbaording_background.dart';
|
||||
import 'package:food_delivery_client/feature/onboarding/presentation/pages/onboarding_page/widgets/w_onboarding_body.dart';
|
||||
|
||||
import '../../../../../food_delivery_client.dart';
|
||||
|
||||
class OnboardingPage extends StatelessWidget {
|
||||
class OnboardingPage extends StatefulWidget {
|
||||
const OnboardingPage({super.key});
|
||||
|
||||
@override
|
||||
State<OnboardingPage> createState() => _OnboardingPageState();
|
||||
}
|
||||
|
||||
class _OnboardingPageState extends State<OnboardingPage> {
|
||||
late PageController _pageController;
|
||||
int currentIndex = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_pageController = PageController(initialPage: 0);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_pageController.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void onPressed() {
|
||||
setState(() {
|
||||
currentIndex++;
|
||||
});
|
||||
_pageController.animateToPage(
|
||||
currentIndex,
|
||||
duration: TimeDelayConst.durationMill300,
|
||||
curve: Curves.easeIn,
|
||||
);
|
||||
}
|
||||
|
||||
void onPageChanged(int int) {
|
||||
setState(() {
|
||||
currentIndex = int;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WLayout(child: Scaffold());
|
||||
return WLayout(
|
||||
bottom: false,
|
||||
child: Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
WOnBoardingBackground(),
|
||||
WOnBoardingBody(
|
||||
pageController: _pageController,
|
||||
onPageChanged: onPageChanged,
|
||||
),
|
||||
Positioned(
|
||||
bottom: 18,
|
||||
left: 24,
|
||||
right: 24,
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
AnimatedDotsIndicator(count: 2, activeIndex: currentIndex),
|
||||
40.verticalSpace,
|
||||
AppButton(
|
||||
name: currentIndex == 0
|
||||
? context.loc.onboarding_button_next
|
||||
: context.loc.onboarding_button_get_started,
|
||||
onPressed: () {
|
||||
if (currentIndex < 1) {
|
||||
onPressed();
|
||||
}
|
||||
if (currentIndex == 1) {
|
||||
log("Navigate to login");
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class Onboarding2 extends StatelessWidget {
|
||||
const Onboarding2({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: context.h,
|
||||
width: context.w,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(AppIcons.icOnBoarding2),
|
||||
SvgPicture.asset(AppIcons.icOnBoarding3),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: context.theme.scaffoldBackgroundColor,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.cD6D4D4.newWithOpacity(.25),
|
||||
offset: Offset(0, 0),
|
||||
blurRadius: 10,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
spacing: 20,
|
||||
children: [
|
||||
25.verticalSpace,
|
||||
Text(
|
||||
"Bringing the best flavors food in the world",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
"Discover your favorite meals and get them delivered fast wherever you are.",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
).paddingSymmetric(horizontal: 22),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WOnBoardingBackground extends StatelessWidget {
|
||||
const WOnBoardingBackground({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Positioned.fill(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(child: SizedBox.expand()),
|
||||
Expanded(
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: context.appThemeColors.onBoardingColor,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.appThemeColors.boxShadow.newWithOpacity(.25),
|
||||
offset: Offset(0, 0),
|
||||
blurRadius: 10,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: SizedBox.expand(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WOnBoardingBody extends StatelessWidget {
|
||||
const WOnBoardingBody({
|
||||
super.key,
|
||||
required this.pageController,
|
||||
required this.onPageChanged,
|
||||
});
|
||||
|
||||
final PageController pageController;
|
||||
final Function(int value) onPageChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<String> titles = [
|
||||
context.loc.onboarding_title_1,
|
||||
context.loc.onboarding_title_1,
|
||||
];
|
||||
final List<String> descriptions = [
|
||||
context.loc.onboarding_subtitle_1,
|
||||
context.loc.onboarding_subtitle_2,
|
||||
];
|
||||
|
||||
final List<Widget> children = [
|
||||
SvgPicture.asset(AppIcons.icOnBoarding1),
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Positioned(
|
||||
top: 80,
|
||||
left: 40,
|
||||
child: SvgPicture.asset(AppIcons.icOnBoarding2),
|
||||
),
|
||||
SvgPicture.asset(AppIcons.icOnBoarding3),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
return Positioned.fill(
|
||||
child: PageView.builder(
|
||||
itemCount: titles.length,
|
||||
controller: pageController,
|
||||
scrollDirection: Axis.horizontal,
|
||||
onPageChanged: onPageChanged,
|
||||
itemBuilder: (context, index) => Column(
|
||||
children: [
|
||||
Expanded(child: children[index]),
|
||||
Expanded(
|
||||
child: Column(
|
||||
spacing: 20,
|
||||
children: [
|
||||
25.verticalSpace,
|
||||
Text(
|
||||
titles[index],
|
||||
textAlign: TextAlign.center,
|
||||
style: context.appThemeTextStyles.size24SemiBold,
|
||||
),
|
||||
Text(
|
||||
descriptions[index],
|
||||
textAlign: TextAlign.center,
|
||||
style: AppTextStyles.size14Regular.copyWith(
|
||||
color: AppColors.cA9A9A9,
|
||||
),
|
||||
),
|
||||
],
|
||||
).paddingSymmetric(horizontal: 22),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user