finished if - then - save button design

This commit is contained in:
ashrafzarkanisala
2024-06-12 20:30:34 +03:00
parent bfbc2e55ce
commit 17e9826b21
9 changed files with 397 additions and 44 deletions

View File

@ -24,7 +24,7 @@ class CreateSceneView extends StatelessWidget {
margin: const EdgeInsets.symmetric(vertical: 4), margin: const EdgeInsets.symmetric(vertical: 4),
child: const SceneListTile( child: const SceneListTile(
assetPath: Assets.handClickIcon, assetPath: Assets.handClickIcon,
title: StringsManager.tapToRun, titleString: StringsManager.tapToRun,
subtitle: StringsManager.turnOffAllLights, subtitle: StringsManager.turnOffAllLights,
), ),
onTap: () => Navigator.pushNamed( onTap: () => Navigator.pushNamed(
@ -38,7 +38,7 @@ class CreateSceneView extends StatelessWidget {
margin: const EdgeInsets.symmetric(vertical: 4), margin: const EdgeInsets.symmetric(vertical: 4),
child: const SceneListTile( child: const SceneListTile(
assetPath: Assets.refreshIcon, assetPath: Assets.refreshIcon,
title: StringsManager.whenDeviceStatusChanges, titleString: StringsManager.whenDeviceStatusChanges,
subtitle: StringsManager.whenUnusualActivityIsDetected, subtitle: StringsManager.whenUnusualActivityIsDetected,
), ),
onTap: () => Navigator.pushNamed( onTap: () => Navigator.pushNamed(

View File

@ -1,12 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/auth/view/widgets/login_divider.dart'; import 'package:syncrow_app/features/scene/view/widgets/if_then_containers/if_container.dart';
import 'package:syncrow_app/features/scene/view/widgets/scene_list_tile.dart'; import 'package:syncrow_app/features/scene/view/widgets/if_then_containers/then_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart'; import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
@ -17,7 +17,7 @@ class SceneAddTasksView extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DefaultScaffold( return DefaultScaffold(
title: StringsManager.createScene, title: StringsManager.createScene,
padding: const EdgeInsets.only(top: 24), padding: EdgeInsets.zero,
actions: [ actions: [
SizedBox( SizedBox(
width: 40, width: 40,
@ -32,38 +32,49 @@ class SceneAddTasksView extends StatelessWidget {
), ),
), ),
], ],
child: SingleChildScrollView( child: Stack(
child: Column( children: [
children: [ const SingleChildScrollView(
DefaultContainer( child: Column(
padding: EdgeInsets.zero, mainAxisSize: MainAxisSize.min,
child: Column( children: [
mainAxisSize: MainAxisSize.min, SizedBox(
children: [ height: 24,
Padding( ),
padding: const EdgeInsets.all(16.0), // IF
child: Row( IFDefaultContainer(),
mainAxisAlignment: MainAxisAlignment.spaceBetween, SizedBox(
children: [ height: 8,
const BodyLarge( ),
text: 'IF', // THEN
), ThenDefaultContainer(),
SvgPicture.asset(Assets.addIcon), SizedBox(
], height: 100,
), ),
],
),
),
Positioned(
bottom: 16,
right: 40,
left: 40,
child: SizedBox(
width: context.width * 0.8,
child: DefaultButton(
onPressed: () {},
customButtonStyle: ButtonStyle(
backgroundColor: WidgetStateProperty.all<Color>(
ColorsManager.primaryColorWithOpacity,
), ),
const Divider( ),
color: ColorsManager.greyColor, child: BodyLarge(
), text: 'Save',
const SceneListTile( style: context.bodyLarge.copyWith(color: Colors.white),
assetPath: Assets.handClickIcon, ),
title: StringsManager.tapToRun,
)
],
), ),
), ),
], )
), ],
), ),
); );
} }

View File

@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/scene/view/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class IFDefaultContainer extends StatelessWidget {
const IFDefaultContainer({
super.key,
});
@override
Widget build(BuildContext context) {
return DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 2),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SceneListTile(
leadingWidget: BodyLarge(
text: 'IF',
style: context.bodyLarge.copyWith(
fontWeight: FontWeight.bold,
color: ColorsManager.primaryTextColor,
),
),
trailingWidget: SvgPicture.asset(Assets.addIcon),
padding: EdgeInsets.zero,
),
const Divider(
color: ColorsManager.greyColor,
thickness: 0.3,
),
const SceneListTile(
assetPath: Assets.handClickIcon,
titleString: StringsManager.tapToRun,
padding: EdgeInsets.zero,
)
],
),
);
}
}

View File

@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/scene/view/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class ThenDefaultContainer extends StatelessWidget {
const ThenDefaultContainer({
super.key,
});
@override
Widget build(BuildContext context) {
return DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 2),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SceneListTile(
leadingWidget: BodyLarge(
text: 'Then',
style: context.bodyLarge.copyWith(
fontWeight: FontWeight.bold,
color: ColorsManager.primaryTextColor,
),
),
trailingWidget: GestureDetector(
onTap: () => context.customBottomSheet(title: 'Add Task'),
child: SvgPicture.asset(
Assets.addIcon,
colorFilter: const ColorFilter.mode(
ColorsManager.primaryColor,
BlendMode.srcIn,
),
),
),
padding: EdgeInsets.zero,
),
const Divider(
color: ColorsManager.greyColor,
thickness: 0.3,
),
SceneListTile(
titleString: '+ Add Task',
textAlign: TextAlign.center,
onPressed: () => context.customBottomSheet(
title: 'Add Task',
titleStyle: context.bodyLarge.copyWith(
color: ColorsManager.primaryColorWithOpacity,
fontWeight: FontWeight.bold,
)),
)
],
),
);
}
}

View File

@ -2,30 +2,50 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SceneListTile extends StatelessWidget { class SceneListTile extends StatelessWidget {
const SceneListTile({ const SceneListTile({
super.key, super.key,
required this.assetPath, this.assetPath,
required this.title, this.titleString,
this.subtitle, this.subtitle,
this.leadingWidget,
this.trailingWidget,
this.padding,
this.textAlign,
this.onPressed,
}); });
final String assetPath; final String? assetPath;
final String title; final String? titleString;
final String? subtitle; final String? subtitle;
final Widget? leadingWidget;
final Widget? trailingWidget;
final EdgeInsetsGeometry? padding;
final TextAlign? textAlign;
final void Function()? onPressed;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListTile( return ListTile(
minLeadingWidth: 40, minLeadingWidth: 40,
leading: SvgPicture.asset( leading: leadingWidget ??
assetPath, (assetPath != null
width: 20, ? SvgPicture.asset(
height: 32, assetPath ?? Assets.assetsImagesLogo,
width: 20,
height: 32,
)
: null),
trailing: trailingWidget,
contentPadding: padding,
title: BodyMedium(
text: titleString ?? '',
textAlign: textAlign,
style: context.bodyMedium.copyWith(fontSize: 15),
), ),
title: BodyMedium(text: title),
subtitle: subtitle == null subtitle: subtitle == null
? null ? null
: BodySmall( : BodySmall(
@ -33,6 +53,7 @@ class SceneListTile extends StatelessWidget {
style: context.bodySmall.copyWith( style: context.bodySmall.copyWith(
fontWeight: FontWeight.w400, color: ColorsManager.greyColor), fontWeight: FontWeight.w400, color: ColorsManager.greyColor),
), ),
onTap: onPressed,
); );
} }
} }

View File

@ -0,0 +1,108 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class CustomBottomSheetWidget extends StatelessWidget {
const CustomBottomSheetWidget({
required this.title,
super.key,
this.onPressed,
this.withBack = false,
this.image = '',
this.imageSize = 200,
this.description = '',
this.onPressedColor = ColorsManager.primaryTextColor,
this.titleStyle,
this.descreptionStyle,
this.backColor,
this.onPressedTitle,
this.imageSpace = 8,
});
final String image;
final double imageSize;
final double imageSpace;
final String title;
final TextStyle? titleStyle;
final String description;
final TextStyle? descreptionStyle;
final bool withBack;
final String? onPressedTitle;
final void Function()? onPressed;
final Color onPressedColor;
final Color? backColor;
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (image.isNotEmpty)
Image.asset(
image,
width: imageSize,
),
if (image.isNotEmpty) SizedBox(height: imageSpace),
if (title.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Text(
title,
style: titleStyle ??
context.bodyLarge.copyWith(
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.center,
),
),
if (title.isNotEmpty) const SizedBox(height: 16),
if (description.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
description,
style: descreptionStyle ?? context.bodyLarge,
textAlign: TextAlign.center,
),
),
if (onPressed != null)
Padding(
padding: EdgeInsets.only(
left: 16,
right: 16,
top: 32,
bottom: withBack ? 0 : 32,
),
child: DefaultButton(
onPressed: onPressed,
child: BodyMedium(
text: onPressedTitle ?? '',
),
),
),
if (withBack)
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 32),
child: DefaultButton(
onPressed: () {
Navigator.pop(context);
},
customButtonStyle: ButtonStyle(
backgroundColor: WidgetStateProperty.all(
backColor ?? ColorsManager.primaryColor),
),
customTextStyle: context.bodyMedium.copyWith(
color: backColor ?? ColorsManager.primaryTextColor),
enabled: true,
child: const BodyMedium(text: 'Back'),
),
),
],
),
);
}
}

View File

@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/utils/context_extension.dart';
class CustomBottomSheet extends StatelessWidget {
const CustomBottomSheet({
super.key,
this.child,
this.height,
this.maxHeight,
this.radius = 20,
this.withClosed = true,
});
final Widget? child;
final double? height;
final double? maxHeight;
final double radius;
final bool withClosed;
@override
Widget build(BuildContext context) {
final bottom = MediaQuery.of(context).viewInsets.bottom;
return SafeArea(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: height ?? 250,
maxHeight: maxHeight ?? context.height * 0.8,
),
child: SingleChildScrollView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
physics: bottom == 0
? const NeverScrollableScrollPhysics()
: const BouncingScrollPhysics(),
child: AnimatedContainer(
duration: const Duration(milliseconds: 50),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
),
padding: EdgeInsets.only(bottom: bottom),
child: child ?? const SizedBox(),
),
),
),
);
}
}

View File

@ -1,4 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/bottom_sheet/bottom_sheet_widget.dart';
import 'package:syncrow_app/features/shared_widgets/bottom_sheet/custom_bottom_sheet.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
extension ContextExtension on BuildContext { extension ContextExtension on BuildContext {
Future<void> goTo(String newRouteName) async { Future<void> goTo(String newRouteName) async {
@ -30,4 +33,60 @@ extension ContextExtension on BuildContext {
TextStyle get bodyMedium => Theme.of(this).textTheme.bodyMedium!; TextStyle get bodyMedium => Theme.of(this).textTheme.bodyMedium!;
TextStyle get bodySmall => Theme.of(this).textTheme.bodySmall!; TextStyle get bodySmall => Theme.of(this).textTheme.bodySmall!;
void customBottomSheet({
/// this fild will show the title after image widget
required String title,
/// this showing image in top of the screen
String? image,
/// this if you need change image size
double? imageSize,
/// if you need change title styling use this fild
TextStyle? titleStyle,
/// this fild will show the title after title widget
String? descreption,
/// if you neee change descreption styling use this fild
TextStyle? descreptionStyle,
/// if you need show back bottom to closed bottom sheet
bool? withBack,
/// this calling when press action bottom
void Function()? onPressed,
/// this fild to change on press text
String? onPressedTitle,
/// this fild to change action bottom color
Color? onPressedColor,
/// this fild to change back bottom color
Color? backColor,
}) {
showModalBottomSheet<void>(
context: this,
isScrollControlled: true,
builder: (BuildContext context) {
return CustomBottomSheet(
child: CustomBottomSheetWidget(
image: image ?? '',
imageSize: imageSize ?? 200,
titleStyle: titleStyle,
description: descreption ?? '',
descreptionStyle: descreptionStyle,
title: title,
withBack: withBack ?? false,
onPressed: onPressed,
onPressedColor: onPressedColor ?? ColorsManager.primaryTextColor,
backColor: backColor,
),
);
},
);
}
} }

View File

@ -6,9 +6,11 @@ abstract class ColorsManager {
static const Color primaryColor = Color(0xFF0030CB); static const Color primaryColor = Color(0xFF0030CB);
static Color primaryColorWithOpacity = static Color primaryColorWithOpacity =
const Color(0xFF023DFE).withOpacity(0.6); const Color(0xFF023DFE).withOpacity(0.6);
static const Color onPrimaryColor = Colors.white; static const Color onPrimaryColor = Colors.white;
static const Color secondaryColor = Color(0xFF023DFE); static const Color secondaryColor = Color(0xFF023DFE);
static const Color onSecondaryColor = Color(0xFF023DFE); static const Color onSecondaryColor = Color(0xFF023DFE);
static const Color primaryTextColor = Colors.black; static const Color primaryTextColor = Colors.black;
static const Color greyColor = Color(0xFFd5d5d5); static const Color greyColor = Color(0xFFd5d5d5);