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

Add inheritMaterialTheme and inheritCupertinoTheme to show() #167

Merged
merged 3 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from all 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Hide backdrop content in screenshot mode
* [#165](https://github.com/wiredashio/wiredash-sdk/pull/165) Validate email address
* [#166](https://github.com/wiredashio/wiredash-sdk/pull/166) Make email address optional. Set `WiredashFeedbackOptions(askForUserEmail: true)` to enable it
* [#167](https://github.com/wiredashio/wiredash-sdk/pull/167) New `inheritMaterialTheme` and `inheritCupertinoTheme` properties for `Wiredash.of(context).show()` to inherit the theme

## 1.0.0-alpha.1 - A Whole New World
* Completely rewritten UI layer
Expand Down
2 changes: 1 addition & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class _HomePage extends StatelessWidget {
/// Since the `Wiredash` widget is at the root of the widget tree this
/// method can be accessed from anywhere in the code.
onPressed: () {
Wiredash.of(context).show(context);
Wiredash.of(context).show(inheritMaterialTheme: true);
},
child: Icon(Icons.feedback_outlined),
),
Expand Down
21 changes: 21 additions & 0 deletions lib/src/common/utils/context_cache.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:flutter/widgets.dart';
import 'package:wiredash/wiredash.dart';

/// Use to bind the [BuildContext] to the current [Wiredash] widget
final Expando _expando = Expando();

extension WiredashWithBuildContext on Wiredash {
/// The context that is attached to the Wiredash widget using
/// `Wiredash.of(context)`
BuildContext? get showBuildContext {
return _expando[this] as BuildContext?;
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm a bit proud of this 😁

}

/// Attach a [BuildContext] to the this [Wiredash] widget
///
/// This setter creates a weak reference to the context. It is free for
/// garbage collection once the [Wiredash] widget gets garbage collected
set showBuildContext(BuildContext? context) {
_expando[this] = context;
}
}
8 changes: 8 additions & 0 deletions lib/src/feedback/wiredash_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import 'package:wiredash/src/common/options/feedback_options.dart';
import 'package:wiredash/src/common/services/services.dart';
import 'package:wiredash/src/common/theme/wiredash_theme_data.dart';
import 'package:wiredash/src/feedback/data/retrying_feedback_submitter.dart';
import 'package:wiredash/src/wiredash_controller.dart';
import 'package:wiredash/src/wiredash_widget.dart';

class WiredashModel with ChangeNotifier {
WiredashModel(this.services);
Expand All @@ -29,6 +31,12 @@ class WiredashModel with ChangeNotifier {
notifyListeners();
}

/// Temporary theme that overrides the `Wiredash.theme` property for the
/// current 'show' session
///
/// Also see
/// - [Wiredash.of]
/// - [WiredashController.show]
WiredashThemeData? _themeFromContext;
WiredashThemeData? get themeFromContext => _themeFromContext;

Expand Down
51 changes: 22 additions & 29 deletions lib/src/wiredash_controller.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:wiredash/src/common/build_info/build_info.dart';
import 'package:wiredash/src/common/utils/context_cache.dart';
import 'package:wiredash/src/feedback/wiredash_model.dart';
import 'package:wiredash/wiredash.dart';

Expand Down Expand Up @@ -86,41 +87,33 @@ class WiredashController {
///
/// If a Wiredash feedback flow is already active (=a feedback sheet is open),
/// does nothing.
void show([BuildContext? context]) {
void show({bool? inheritMaterialTheme, bool? inheritCupertinoTheme}) {
assert(
() {
if (inheritCupertinoTheme == true && inheritMaterialTheme == true) {
throw 'You can not enabled both, '
'inheritCupertinoTheme and inheritMaterialTheme';
}
return true;
}(),
);
// reset theme at every call
_model.themeFromContext = null;
final context = _model.services.wiredashWidget.showBuildContext;
if (context != null) {
// generate theme from current context
final materialTheme = Theme.of(context);
final cupertinoTheme = CupertinoTheme.of(context);
final materialColor = materialTheme.colorScheme.secondary;
final cupertinoColor = cupertinoTheme.primaryColor;

late Color color;
const defaultCupertinoTheme = CupertinoThemeData();
// When the primary cupertino color is set, use this one
if (defaultCupertinoTheme.primaryColor != cupertinoColor) {
color = cupertinoColor;
} else {
// always fallback to material color, which is more likely to be set
// in the flutter world
color = materialColor;
}

late Brightness brightness;
if (materialTheme.brightness == Brightness.dark ||
cupertinoTheme.brightness == Brightness.dark) {
// When one is dark, assume either of them is explicitly set
brightness = Brightness.dark;
} else {
// fallback to light
brightness = Brightness.light;
if (inheritMaterialTheme == true) {
final materialTheme = Theme.of(context);
_model.themeFromContext = WiredashThemeData.fromColor(
color: materialTheme.colorScheme.secondary,
brightness: materialTheme.brightness,
);
}

if (materialTheme != ThemeData.fallback()) {
if (inheritCupertinoTheme == true) {
final cupertinoTheme = CupertinoTheme.of(context);
_model.themeFromContext = WiredashThemeData.fromColor(
color: color,
brightness: brightness,
color: cupertinoTheme.primaryColor,
brightness: cupertinoTheme.brightness ?? Brightness.light,
);
}
}
Expand Down
17 changes: 13 additions & 4 deletions lib/src/wiredash_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:wiredash/src/common/options/wiredash_options.dart';
import 'package:wiredash/src/common/services/services.dart';
import 'package:wiredash/src/common/theme/wiredash_theme.dart';
import 'package:wiredash/src/common/utils/context_cache.dart';
import 'package:wiredash/src/common/utils/project_credential_validator.dart';
import 'package:wiredash/src/common/widgets/screencapture.dart';
import 'package:wiredash/src/feedback/backdrop/backdrop_controller_provider.dart';
Expand Down Expand Up @@ -121,7 +122,9 @@ class Wiredash extends StatefulWidget {
static WiredashController? maybeOf(BuildContext context) {
final state = context.findAncestorStateOfType<WiredashState>();
if (state == null) return null;

// cache context in a short lived object like the widget
// it gets later retrieved by the `show()` method to read the theme
state.widget.showBuildContext = context;
return WiredashController(state._services.wiredashModel);
}

Expand All @@ -135,7 +138,13 @@ class Wiredash extends StatefulWidget {
/// ```
static WiredashController of(BuildContext context) {
final state = context.findAncestorStateOfType<WiredashState>();
return WiredashController(state!._services.wiredashModel);
if (state == null) {
throw StateError('Could not find WiredashState in ancestors');
}
// cache context in a short lived object like the widget
// it gets later retrieved by the `show()` method to read the theme
state.widget.showBuildContext = context;
return WiredashController(state._services.wiredashModel);
}
}

Expand Down Expand Up @@ -201,8 +210,8 @@ class WiredashState extends State<Wiredash> {

@override
Widget build(BuildContext context) {
final theme = widget.theme ??
_services.wiredashModel.themeFromContext ??
final theme = _services.wiredashModel.themeFromContext ??
widget.theme ??
WiredashThemeData();

// Assign app an key so it doesn't lose state when wrapped, unwrapped
Expand Down