|
| 1 | +import 'dart:math' show sqrt; |
| 2 | + |
1 | 3 | import 'package:flutter/material.dart'; |
2 | 4 | import 'posthog_display_survey_appearance.dart'; |
3 | 5 |
|
4 | 6 | /// Appearance configuration for survey widgets |
5 | 7 | @immutable |
6 | 8 | class SurveyAppearance { |
7 | 9 | const SurveyAppearance({ |
8 | | - this.backgroundColor, |
| 10 | + this.backgroundColor = Colors.white, |
9 | 11 | this.submitButtonColor = Colors.black, |
10 | 12 | this.submitButtonText = 'Submit', |
11 | 13 | this.submitButtonTextColor = Colors.white, |
12 | | - this.descriptionTextColor, |
13 | | - this.ratingButtonColor, |
14 | | - this.ratingButtonActiveColor, |
| 14 | + this.descriptionTextColor = Colors.black, |
| 15 | + this.questionTextColor = Colors.black, |
| 16 | + this.closeButtonColor = Colors.black, |
| 17 | + this.ratingButtonColor = const Color(0xFFEEEEEE), |
| 18 | + this.ratingButtonActiveColor = Colors.black, |
| 19 | + this.ratingButtonSelectedTextColor = Colors.white, |
| 20 | + this.ratingButtonUnselectedTextColor = const Color(0x80000000), |
15 | 21 | this.displayThankYouMessage = true, |
16 | 22 | this.thankYouMessageHeader = 'Thank you for your feedback!', |
17 | 23 | this.thankYouMessageDescription, |
18 | 24 | this.thankYouMessageCloseButtonText = 'Close', |
19 | | - this.borderColor, |
| 25 | + this.borderColor = const Color(0xFFBDBDBD), |
| 26 | + this.inputBackgroundColor = Colors.white, |
| 27 | + this.inputTextColor = Colors.black, |
| 28 | + this.inputPlaceholderColor = const Color(0xFF757575), |
| 29 | + this.choiceButtonBorderColor = Colors.black, |
| 30 | + this.choiceButtonTextColor = Colors.black, |
20 | 31 | }); |
21 | 32 |
|
22 | | - final Color? backgroundColor; |
| 33 | + final Color backgroundColor; |
23 | 34 | final Color submitButtonColor; |
24 | 35 | final String submitButtonText; |
25 | 36 | final Color submitButtonTextColor; |
26 | | - final Color? descriptionTextColor; |
27 | | - final Color? ratingButtonColor; |
28 | | - final Color? ratingButtonActiveColor; |
| 37 | + final Color descriptionTextColor; |
| 38 | + final Color questionTextColor; |
| 39 | + final Color closeButtonColor; |
| 40 | + final Color ratingButtonColor; |
| 41 | + final Color ratingButtonActiveColor; |
| 42 | + final Color ratingButtonSelectedTextColor; |
| 43 | + final Color ratingButtonUnselectedTextColor; |
29 | 44 | final bool displayThankYouMessage; |
30 | 45 | final String thankYouMessageHeader; |
31 | 46 | final String? thankYouMessageDescription; |
32 | 47 | final String thankYouMessageCloseButtonText; |
33 | | - final Color? borderColor; |
| 48 | + final Color borderColor; |
| 49 | + final Color inputBackgroundColor; |
| 50 | + final Color inputTextColor; |
| 51 | + final Color inputPlaceholderColor; |
| 52 | + final Color choiceButtonBorderColor; |
| 53 | + final Color choiceButtonTextColor; |
34 | 54 |
|
35 | 55 | /// Creates a [SurveyAppearance] from a [PostHogDisplaySurveyAppearance] |
36 | 56 | static SurveyAppearance fromPostHog( |
37 | 57 | PostHogDisplaySurveyAppearance? appearance) { |
| 58 | + final backgroundColor = |
| 59 | + _colorFromHex(appearance?.backgroundColor) ?? Colors.white; |
| 60 | + final submitButtonColor = |
| 61 | + _colorFromHex(appearance?.submitButtonColor) ?? Colors.black; |
| 62 | + final ratingButtonColor = |
| 63 | + _colorFromHex(appearance?.ratingButtonColor) ?? const Color(0xFFEEEEEE); |
| 64 | + final ratingButtonActiveColor = |
| 65 | + _colorFromHex(appearance?.ratingButtonActiveColor) ?? Colors.black; |
| 66 | + |
| 67 | + // Input background: use override, or slight adjustment for high luminance backgrounds |
| 68 | + final inputBackgroundColor = _colorFromHex(appearance?.inputBackground) ?? |
| 69 | + (backgroundColor.computeLuminance() > 0.95 |
| 70 | + ? const Color(0xFFF8F8F8) |
| 71 | + : backgroundColor); |
| 72 | + |
| 73 | + // Primary text color: use textColor override if provided, otherwise auto-contrast |
| 74 | + final primaryTextColor = _colorFromHex(appearance?.textColor) ?? |
| 75 | + _getContrastingTextColor(backgroundColor); |
| 76 | + |
| 77 | + // Input text color: use override if provided, otherwise auto-contrast from input background |
| 78 | + final inputTextColor = _colorFromHex(appearance?.inputTextColor) ?? |
| 79 | + _getContrastingTextColor(inputBackgroundColor); |
| 80 | + |
38 | 81 | return SurveyAppearance( |
39 | | - backgroundColor: _colorFromHex(appearance?.backgroundColor), |
40 | | - submitButtonColor: |
41 | | - _colorFromHex(appearance?.submitButtonColor) ?? Colors.black, |
| 82 | + backgroundColor: backgroundColor, |
| 83 | + submitButtonColor: submitButtonColor, |
42 | 84 | submitButtonText: appearance?.submitButtonText ?? 'Submit', |
43 | | - submitButtonTextColor: |
44 | | - _colorFromHex(appearance?.submitButtonTextColor) ?? Colors.white, |
45 | | - descriptionTextColor: _colorFromHex(appearance?.descriptionTextColor), |
46 | | - ratingButtonColor: _colorFromHex(appearance?.ratingButtonColor), |
47 | | - ratingButtonActiveColor: |
48 | | - _colorFromHex(appearance?.ratingButtonActiveColor), |
| 85 | + submitButtonTextColor: _colorFromHex(appearance?.submitButtonTextColor) ?? |
| 86 | + _getContrastingTextColor(submitButtonColor), |
| 87 | + descriptionTextColor: |
| 88 | + _colorFromHex(appearance?.descriptionTextColor) ?? primaryTextColor, |
| 89 | + questionTextColor: primaryTextColor, |
| 90 | + closeButtonColor: primaryTextColor, |
| 91 | + ratingButtonColor: ratingButtonColor, |
| 92 | + ratingButtonActiveColor: ratingButtonActiveColor, |
| 93 | + ratingButtonSelectedTextColor: |
| 94 | + _getContrastingTextColor(ratingButtonActiveColor), |
| 95 | + ratingButtonUnselectedTextColor: inputTextColor.withAlpha(128), |
49 | 96 | displayThankYouMessage: appearance?.displayThankYouMessage ?? true, |
50 | 97 | thankYouMessageHeader: |
51 | 98 | appearance?.thankYouMessageHeader ?? 'Thank you for your feedback!', |
52 | 99 | thankYouMessageDescription: appearance?.thankYouMessageDescription, |
53 | 100 | thankYouMessageCloseButtonText: |
54 | 101 | appearance?.thankYouMessageCloseButtonText ?? 'Close', |
55 | | - borderColor: _colorFromHex(appearance?.borderColor), |
| 102 | + borderColor: |
| 103 | + _colorFromHex(appearance?.borderColor) ?? const Color(0xFFBDBDBD), |
| 104 | + inputBackgroundColor: inputBackgroundColor, |
| 105 | + inputTextColor: inputTextColor, |
| 106 | + inputPlaceholderColor: inputTextColor.withAlpha(153), |
| 107 | + choiceButtonBorderColor: primaryTextColor, |
| 108 | + choiceButtonTextColor: primaryTextColor, |
56 | 109 | ); |
57 | 110 | } |
58 | 111 |
|
| 112 | + /// Returns black or white text color based on the perceived brightness of the background. |
| 113 | + /// Uses the HSP (Highly Sensitive Perceived) color model for perceived brightness. |
| 114 | + /// This matches the algorithm used in posthog-js. |
| 115 | + static Color _getContrastingTextColor(Color color) { |
| 116 | + final r = color.red; |
| 117 | + final g = color.green; |
| 118 | + final b = color.blue; |
| 119 | + // HSP equation for perceived brightness |
| 120 | + final hsp = sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b)); |
| 121 | + // Using 127.5 as threshold (same as JS) |
| 122 | + return hsp > 127.5 ? Colors.black : Colors.white; |
| 123 | + } |
| 124 | + |
59 | 125 | static Color? _colorFromHex(String? colorString) { |
60 | 126 | if (colorString == null || colorString.isEmpty) return null; |
61 | 127 |
|
|
0 commit comments