Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#38 Implement a dark mode #241

Merged
merged 14 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions feedback/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class _MyAppState extends State<MyApp> {
Colors.yellow,
],
),
darkTheme: FeedbackThemeData.dark(),
localizationsDelegates: [
GlobalFeedbackLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
Expand Down
33 changes: 29 additions & 4 deletions feedback/lib/src/better_feedback.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,20 @@ class FeedbackSheetDragHandle extends StatelessWidget {

@override
Widget build(BuildContext context) {
final FeedbackThemeData feedbackTheme = FeedbackTheme.of(context);
return IgnorePointer(
child: Container(
height: 20,
padding: const EdgeInsets.symmetric(vertical: 7.5),
alignment: Alignment.center,
color: FeedbackTheme.of(context).feedbackSheetColor,
color: feedbackTheme.feedbackSheetColor,
child: Container(
height: 5,
width: 30,
decoration: BoxDecoration(
color: Colors.black26,
color: feedbackTheme.brightness == Brightness.light
? Colors.black26
: Colors.white38,
ueman marked this conversation as resolved.
Show resolved Hide resolved
borderRadius: BorderRadius.circular(5),
),
),
Expand Down Expand Up @@ -104,7 +107,9 @@ class BetterFeedback extends StatefulWidget {
Key? key,
required this.child,
this.feedbackBuilder,
this.themeMode,
this.theme,
this.darkTheme,
this.localizationsDelegates,
this.localeOverride,
this.mode = FeedbackMode.draw,
Expand All @@ -125,9 +130,27 @@ class BetterFeedback extends StatefulWidget {
/// prompt for input.
final FeedbackBuilder? feedbackBuilder;

/// The Theme, which gets used to style the feedback ui.
/// Determines which theme will be used by the Feedback UI.
/// If set to ThemeMode.system, the choice of which theme to use will be based
/// on the user's system preferences (using the MediaQuery.platformBrightnessOf).
/// If set to ThemeMode.light the [theme] will be used, regardless of the user's
/// system preference. If [theme] isn't provided [FeedbackThemeData()] will
/// be used.
/// If set to ThemeMode.dark the [darkTheme] will be used regardless of the
/// user's system preference. If [darkTheme] isn't provided, will fallback to
/// [theme]. If both [darkTheme] and [theme] aren't provided
/// [FeedbackThemeData.dark()] will be used.
/// The default value is ThemeMode.system.
apomalyn marked this conversation as resolved.
Show resolved Hide resolved
final ThemeMode? themeMode;

/// The Theme, which gets used to style the feedback ui if the [themeMode] is
/// ThemeMode.light or user's system preference is light.
final FeedbackThemeData? theme;

/// The theme, which gets used to style the feedback ui if the [themeMode] is
/// ThemeMode.dark or user's system preference is dark.
final FeedbackThemeData? darkTheme;

/// The delegates for this library's FeedbackLocalization widget.
/// You need to supply the following delegates if you choose to customize it.
/// [MaterialLocalizations]
Expand Down Expand Up @@ -198,7 +221,9 @@ class _BetterFeedbackState extends State<BetterFeedback> {
@override
Widget build(BuildContext context) {
return FeedbackApp(
data: widget.theme,
themeMode: widget.themeMode,
theme: widget.theme,
darkTheme: widget.darkTheme,
localizationsDelegates: widget.localizationsDelegates,
localeOverride: widget.localeOverride,
child: Builder(builder: (context) {
Expand Down
261 changes: 136 additions & 125 deletions feedback/lib/src/feedback_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,15 @@
final animation = Tween<double>(begin: 0, end: 1)
.chain(CurveTween(curve: Curves.easeInSine))
.animate(_controller);

final FeedbackThemeData feedbackThemeData = FeedbackTheme.of(context);
final ThemeData theme = ThemeData(
brightness: feedbackThemeData.brightness,
cardColor: feedbackThemeData.feedbackSheetColor,
colorScheme: feedbackThemeData.brightness == Brightness.dark
? ColorScheme.dark(background: feedbackThemeData.background)
: ColorScheme.light(background: feedbackThemeData.background));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably go into the theme

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried a different approach for this one, let me hear your thoughts! 😄


// We need to supply a navigator because `TextField` and other widgets that
// could be used in the bottom feedback sheet require a navigator.
// The navigator needs to be above the custom layout instead of just around
Expand All @@ -143,145 +152,147 @@
onGenerateRoute: (_) {
return MaterialPageRoute<void>(
builder: (context) {
return Material(
color: FeedbackTheme.of(context).background,
child: AnimatedBuilder(
animation: _controller,
// Place the screenshot here so that the widget tree isn't being
// arbitrarily rebuilt.
child: Screenshot(
controller: screenshotController,
child: PaintOnChild(
controller: painterController,
isPaintingActive:
mode == FeedbackMode.draw && widget.isFeedbackVisible,
child: widget.child,
),
),
builder: (context, screenshotChild) {
return CustomMultiChildLayout(
delegate: _FeedbackLayoutDelegate(
displayFeedback: !animation.isDismissed,
query: MediaQuery.of(context),
sheetFraction:
FeedbackTheme.of(context).feedbackSheetHeight,
animationProgress: animation.value,
return Theme(
apomalyn marked this conversation as resolved.
Show resolved Hide resolved
data: theme,
child: Material(
color: FeedbackTheme.of(context).background,
child: AnimatedBuilder(
animation: _controller,
// Place the screenshot here so that the widget tree isn't being
// arbitrarily rebuilt.
child: Screenshot(
controller: screenshotController,
child: PaintOnChild(
controller: painterController,
isPaintingActive:
mode == FeedbackMode.draw && widget.isFeedbackVisible,
child: widget.child,
),
children: [
LayoutId(
id: _screenshotId,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: padding),
child: ScaleAndFade(
progress: sheetProgress,
minScale: .7,
// If opacity reaches zero, flutter will stop
// drawing the child widget which breaks the
// screenshot.
minOpacity: .01,
child:
LayoutBuilder(builder: (context, constraints) {
final size = MediaQuery.of(context).size;
return OverflowBox(
// Allow the screenshot to overflow to the full
// screen size and then scale it down to meet
// it's parent's constraints.
maxWidth: size.width,
maxHeight: size.height,
child: ScaleAndClip(
progress: animation.value,
// Scale down to fit the constraints.
// `_FeedbackLayoutDelegate` ensures that the
// constraints are the same aspect ratio as
// the query size.
scaleFactor:
constraints.maxWidth / size.width,
child: LayoutBuilder(
builder: (context, constraints) {
return screenshotChild!;
}),
),
);
}),
),
),
),
builder: (context, screenshotChild) {
return CustomMultiChildLayout(
delegate: _FeedbackLayoutDelegate(
displayFeedback: !animation.isDismissed,
query: MediaQuery.of(context),
sheetFraction: feedbackThemeData.feedbackSheetHeight,
animationProgress: animation.value,
),
if (!animation.isDismissed)
children: [
LayoutId(
id: _controlsColumnId,
id: _screenshotId,
child: Padding(
padding: EdgeInsets.only(left: padding),
padding: EdgeInsets.symmetric(horizontal: padding),
child: ScaleAndFade(
progress: sheetProgress,
minScale: .7,
child: ControlsColumn(
mode: mode,
activeColor: painterController.drawColor,
colors: widget.drawColors,
onColorChanged: (color) {
setState(() {
painterController.drawColor = color;
});
_hideKeyboard(context);
},
onUndo: () {
painterController.undo();
_hideKeyboard(context);
},
onClearDrawing: () {
painterController.clear();
_hideKeyboard(context);
},
onControlModeChanged: (mode) {
setState(() {
this.mode = mode;
// If opacity reaches zero, flutter will stop
// drawing the child widget which breaks the
// screenshot.
minOpacity: .01,
child: LayoutBuilder(
builder: (context, constraints) {
final size = MediaQuery.of(context).size;
return OverflowBox(
// Allow the screenshot to overflow to the full
// screen size and then scale it down to meet
// it's parent's constraints.
maxWidth: size.width,
maxHeight: size.height,
child: ScaleAndClip(
progress: animation.value,
// Scale down to fit the constraints.
// `_FeedbackLayoutDelegate` ensures that the
// constraints are the same aspect ratio as
// the query size.
scaleFactor:
constraints.maxWidth / size.width,
child: LayoutBuilder(
builder: (context, constraints) {
return screenshotChild!;
}),
),
);
}),
),
),
),
if (!animation.isDismissed)
LayoutId(
id: _controlsColumnId,
child: Padding(
padding: EdgeInsets.only(left: padding),
child: ScaleAndFade(
progress: sheetProgress,
minScale: .7,
child: ControlsColumn(
mode: mode,
activeColor: painterController.drawColor,
colors: widget.drawColors,
onColorChanged: (color) {
setState(() {
painterController.drawColor = color;

Check warning on line 233 in feedback/lib/src/feedback_widget.dart

View check run for this annotation

Codecov / codecov/patch

feedback/lib/src/feedback_widget.dart#L231-L233

Added lines #L231 - L233 were not covered by tests
});
_hideKeyboard(context);
});
},
onCloseFeedback: () {
_hideKeyboard(context);
BetterFeedback.of(context).hide();
},
},
onUndo: () {
painterController.undo();
_hideKeyboard(context);

Check warning on line 239 in feedback/lib/src/feedback_widget.dart

View check run for this annotation

Codecov / codecov/patch

feedback/lib/src/feedback_widget.dart#L237-L239

Added lines #L237 - L239 were not covered by tests
},
onClearDrawing: () {
painterController.clear();
_hideKeyboard(context);

Check warning on line 243 in feedback/lib/src/feedback_widget.dart

View check run for this annotation

Codecov / codecov/patch

feedback/lib/src/feedback_widget.dart#L241-L243

Added lines #L241 - L243 were not covered by tests
},
onControlModeChanged: (mode) {
setState(() {
this.mode = mode;
_hideKeyboard(context);
});
},
onCloseFeedback: () {
_hideKeyboard(context);
BetterFeedback.of(context).hide();
},
),
),
),
),
),
if (!animation.isDismissed)
LayoutId(
id: _sheetId,
child: NotificationListener<
DraggableScrollableNotification>(
onNotification: (notification) {
sheetProgress.value = (notification.extent -
notification.minExtent) /
(notification.maxExtent -
notification.minExtent);
return false;
},
child: FeedbackBottomSheet(
key: const Key('feedback_bottom_sheet'),
feedbackBuilder: widget.feedbackBuilder,
onSubmit: (
String feedback, {
Map<String, dynamic>? extras,
}) async {
await _sendFeedback(
context,
BetterFeedback.of(context).onFeedback!,
screenshotController,
feedback,
widget.pixelRatio,
extras: extras,
);
painterController.clear();
if (!animation.isDismissed)
LayoutId(
id: _sheetId,
child: NotificationListener<
DraggableScrollableNotification>(
onNotification: (notification) {
sheetProgress.value = (notification.extent -
notification.minExtent) /
(notification.maxExtent -
notification.minExtent);

Check warning on line 268 in feedback/lib/src/feedback_widget.dart

View check run for this annotation

Codecov / codecov/patch

feedback/lib/src/feedback_widget.dart#L264-L268

Added lines #L264 - L268 were not covered by tests
return false;
},
sheetProgress: sheetProgress,
child: FeedbackBottomSheet(
key: const Key('feedback_bottom_sheet'),
feedbackBuilder: widget.feedbackBuilder,
onSubmit: (
String feedback, {
Map<String, dynamic>? extras,
}) async {
await _sendFeedback(
context,
BetterFeedback.of(context).onFeedback!,
screenshotController,
feedback,
widget.pixelRatio,
extras: extras,
);
painterController.clear();
},
sheetProgress: sheetProgress,
),
),
),
),
],
);
},
],
);
},
),
),
);
},
Expand Down
Loading
Loading