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

View File

@ -1,12 +1,12 @@
import 'package:flutter/material.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/scene_list_tile.dart';
import 'package:syncrow_app/features/scene/view/widgets/if_then_containers/if_container.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_container.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/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';
@ -17,7 +17,7 @@ class SceneAddTasksView extends StatelessWidget {
Widget build(BuildContext context) {
return DefaultScaffold(
title: StringsManager.createScene,
padding: const EdgeInsets.only(top: 24),
padding: EdgeInsets.zero,
actions: [
SizedBox(
width: 40,
@ -32,38 +32,49 @@ class SceneAddTasksView extends StatelessWidget {
),
),
],
child: SingleChildScrollView(
child: Column(
children: [
DefaultContainer(
padding: EdgeInsets.zero,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
text: 'IF',
),
SvgPicture.asset(Assets.addIcon),
],
),
child: Stack(
children: [
const SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 24,
),
// IF
IFDefaultContainer(),
SizedBox(
height: 8,
),
// THEN
ThenDefaultContainer(),
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,
),
const SceneListTile(
assetPath: Assets.handClickIcon,
title: StringsManager.tapToRun,
)
],
),
child: BodyLarge(
text: 'Save',
style: context.bodyLarge.copyWith(color: Colors.white),
),
),
),
],
),
)
],
),
);
}

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: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/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SceneListTile extends StatelessWidget {
const SceneListTile({
super.key,
required this.assetPath,
required this.title,
this.assetPath,
this.titleString,
this.subtitle,
this.leadingWidget,
this.trailingWidget,
this.padding,
this.textAlign,
this.onPressed,
});
final String assetPath;
final String title;
final String? assetPath;
final String? titleString;
final String? subtitle;
final Widget? leadingWidget;
final Widget? trailingWidget;
final EdgeInsetsGeometry? padding;
final TextAlign? textAlign;
final void Function()? onPressed;
@override
Widget build(BuildContext context) {
return ListTile(
minLeadingWidth: 40,
leading: SvgPicture.asset(
assetPath,
width: 20,
height: 32,
leading: leadingWidget ??
(assetPath != null
? SvgPicture.asset(
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
? null
: BodySmall(
@ -33,6 +53,7 @@ class SceneListTile extends StatelessWidget {
style: context.bodySmall.copyWith(
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: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 {
Future<void> goTo(String newRouteName) async {
@ -30,4 +33,60 @@ extension ContextExtension on BuildContext {
TextStyle get bodyMedium => Theme.of(this).textTheme.bodyMedium!;
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 Color primaryColorWithOpacity =
const Color(0xFF023DFE).withOpacity(0.6);
static const Color onPrimaryColor = Colors.white;
static const Color secondaryColor = Color(0xFF023DFE);
static const Color onSecondaryColor = Color(0xFF023DFE);
static const Color primaryTextColor = Colors.black;
static const Color greyColor = Color(0xFFd5d5d5);