Skip to content

Commit 1eaf17f

Browse files
kyleswankadboiomarandaneto
authored
Improve consistency when handling colors in surveys. (#233)
* Improve consistency when handling colors in surveys. Co-authored-by: Tate <wintermydog@gmail.com> * add auto-contrast and support for textColor, inputBackground, and inputTextColor * fix --------- Co-authored-by: Adam Bowker <adam.b@posthog.com> Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
1 parent fd4be90 commit 1eaf17f

15 files changed

+150
-53
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## Next
22

3+
- chore: improve survey color handling ([#233](https://github.com/PostHog/posthog-flutter/pull/233))
4+
35
- feat: add `beforeSend` callback to `PostHogConfig` for dropping or modifying events before they are sent to PostHog ([#255](https://github.com/PostHog/posthog-flutter/pull/255))
46
- **Limitation**:
57
- Does NOT intercept native-initiated events such as:

android/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ android {
5353
dependencies {
5454
testImplementation 'org.jetbrains.kotlin:kotlin-test'
5555
testImplementation 'org.mockito:mockito-core:5.0.0'
56-
// + Version 3.25.0 and the versions up to 4.0.0, not including 4.0.0 and higher
57-
implementation 'com.posthog:posthog-android:[3.25.0,4.0.0]'
56+
// + Version 3.30.0 and the versions up to 4.0.0, not including 4.0.0 and higher
57+
implementation 'com.posthog:posthog-android:[3.30.0,4.0.0]'
5858
}
5959

6060
testOptions {

android/src/main/kotlin/com/posthog/flutter/PostHogDisplaySurveyExt.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,24 @@ fun PostHogDisplaySurvey.toMap(): Map<String, Any?> {
6060
appearance?.let { app ->
6161
map["appearance"] =
6262
mapOf(
63+
"fontFamily" to app.fontFamily,
6364
"backgroundColor" to app.backgroundColor,
65+
"borderColor" to app.borderColor,
6466
"submitButtonColor" to app.submitButtonColor,
6567
"submitButtonText" to app.submitButtonText,
6668
"submitButtonTextColor" to app.submitButtonTextColor,
69+
"textColor" to app.textColor,
6770
"descriptionTextColor" to app.descriptionTextColor,
6871
"ratingButtonColor" to app.ratingButtonColor,
6972
"ratingButtonActiveColor" to app.ratingButtonActiveColor,
70-
"borderColor" to app.borderColor,
73+
"inputBackground" to app.inputBackground,
74+
"inputTextColor" to app.inputTextColor,
7175
"placeholder" to app.placeholder,
7276
"displayThankYouMessage" to app.displayThankYouMessage,
7377
"thankYouMessageHeader" to app.thankYouMessageHeader,
7478
"thankYouMessageDescription" to app.thankYouMessageDescription,
7579
"thankYouMessageDescriptionContentType" to app.thankYouMessageDescriptionContentType?.value,
80+
"thankYouMessageCloseButtonText" to app.thankYouMessageCloseButtonText,
7681
)
7782
}
7883

ios/Classes/PostHogDisplaySurvey+Dict.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
if let submitButtonTextColor = appearance.submitButtonTextColor {
7070
appearanceDict["submitButtonTextColor"] = submitButtonTextColor
7171
}
72+
if let textColor = appearance.textColor {
73+
appearanceDict["textColor"] = textColor
74+
}
7275
if let descriptionTextColor = appearance.descriptionTextColor {
7376
appearanceDict["descriptionTextColor"] = descriptionTextColor
7477
}
@@ -78,6 +81,12 @@
7881
if let ratingButtonActiveColor = appearance.ratingButtonActiveColor {
7982
appearanceDict["ratingButtonActiveColor"] = ratingButtonActiveColor
8083
}
84+
if let inputBackground = appearance.inputBackground {
85+
appearanceDict["inputBackground"] = inputBackground
86+
}
87+
if let inputTextColor = appearance.inputTextColor {
88+
appearanceDict["inputTextColor"] = inputTextColor
89+
}
8190
if let placeholder = appearance.placeholder {
8291
appearanceDict["placeholder"] = placeholder
8392
}

ios/posthog_flutter.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ Postog flutter plugin
2121
s.ios.dependency 'Flutter'
2222
s.osx.dependency 'FlutterMacOS'
2323

24-
# ~> Version 3.32.0 up to, but not including, 4.0.0
25-
s.dependency 'PostHog', '>= 3.32.0', '< 4.0.0'
24+
# ~> Version 3.38.0 up to, but not including, 4.0.0
25+
s.dependency 'PostHog', '>= 3.38.0', '< 4.0.0'
2626

2727
s.ios.deployment_target = '13.0'
2828
# PH iOS SDK 3.0.0 requires >= 10.15

lib/src/surveys/models/posthog_display_survey.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,12 @@ class PostHogDisplaySurvey {
100100
submitButtonColor: a['submitButtonColor'] as String?,
101101
submitButtonText: a['submitButtonText'] as String?,
102102
submitButtonTextColor: a['submitButtonTextColor'] as String?,
103+
textColor: a['textColor'] as String?,
103104
descriptionTextColor: a['descriptionTextColor'] as String?,
104105
ratingButtonColor: a['ratingButtonColor'] as String?,
105106
ratingButtonActiveColor: a['ratingButtonActiveColor'] as String?,
107+
inputBackground: a['inputBackground'] as String?,
108+
inputTextColor: a['inputTextColor'] as String?,
106109
placeholder: a['placeholder'] as String?,
107110
displayThankYouMessage: a['displayThankYouMessage'] as bool? ?? true,
108111
thankYouMessageHeader: a['thankYouMessageHeader'] as String?,

lib/src/surveys/models/posthog_display_survey_appearance.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ class PostHogDisplaySurveyAppearance {
1111
this.submitButtonColor,
1212
this.submitButtonText,
1313
this.submitButtonTextColor,
14+
this.textColor,
1415
this.descriptionTextColor,
1516
this.ratingButtonColor,
1617
this.ratingButtonActiveColor,
18+
this.inputBackground,
19+
this.inputTextColor,
1720
this.placeholder,
1821
this.displayThankYouMessage = true,
1922
this.thankYouMessageHeader,
@@ -28,9 +31,12 @@ class PostHogDisplaySurveyAppearance {
2831
final String? submitButtonColor;
2932
final String? submitButtonText;
3033
final String? submitButtonTextColor;
34+
final String? textColor;
3135
final String? descriptionTextColor;
3236
final String? ratingButtonColor;
3337
final String? ratingButtonActiveColor;
38+
final String? inputBackground;
39+
final String? inputTextColor;
3440
final String? placeholder;
3541
final bool displayThankYouMessage;
3642
final String? thankYouMessageHeader;

lib/src/surveys/models/survey_appearance.dart

Lines changed: 86 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,127 @@
1+
import 'dart:math' show sqrt;
2+
13
import 'package:flutter/material.dart';
24
import 'posthog_display_survey_appearance.dart';
35

46
/// Appearance configuration for survey widgets
57
@immutable
68
class SurveyAppearance {
79
const SurveyAppearance({
8-
this.backgroundColor,
10+
this.backgroundColor = Colors.white,
911
this.submitButtonColor = Colors.black,
1012
this.submitButtonText = 'Submit',
1113
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),
1521
this.displayThankYouMessage = true,
1622
this.thankYouMessageHeader = 'Thank you for your feedback!',
1723
this.thankYouMessageDescription,
1824
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,
2031
});
2132

22-
final Color? backgroundColor;
33+
final Color backgroundColor;
2334
final Color submitButtonColor;
2435
final String submitButtonText;
2536
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;
2944
final bool displayThankYouMessage;
3045
final String thankYouMessageHeader;
3146
final String? thankYouMessageDescription;
3247
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;
3454

3555
/// Creates a [SurveyAppearance] from a [PostHogDisplaySurveyAppearance]
3656
static SurveyAppearance fromPostHog(
3757
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+
3881
return SurveyAppearance(
39-
backgroundColor: _colorFromHex(appearance?.backgroundColor),
40-
submitButtonColor:
41-
_colorFromHex(appearance?.submitButtonColor) ?? Colors.black,
82+
backgroundColor: backgroundColor,
83+
submitButtonColor: submitButtonColor,
4284
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),
4996
displayThankYouMessage: appearance?.displayThankYouMessage ?? true,
5097
thankYouMessageHeader:
5198
appearance?.thankYouMessageHeader ?? 'Thank you for your feedback!',
5299
thankYouMessageDescription: appearance?.thankYouMessageDescription,
53100
thankYouMessageCloseButtonText:
54101
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,
56109
);
57110
}
58111

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+
59125
static Color? _colorFromHex(String? colorString) {
60126
if (colorString == null || colorString.isEmpty) return null;
61127

lib/src/surveys/widgets/number_rating_button.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ class NumberRatingButton extends StatelessWidget {
2222
@override
2323
Widget build(BuildContext context) {
2424
final buttonColor = isSelected
25-
? appearance.ratingButtonActiveColor ?? Colors.black
26-
: appearance.ratingButtonColor ?? Colors.grey.shade200;
25+
? appearance.ratingButtonActiveColor
26+
: appearance.ratingButtonColor;
2727

2828
return Expanded(
2929
child: Row(
@@ -61,8 +61,8 @@ class NumberRatingButton extends StatelessWidget {
6161
value.toString(),
6262
style: TextStyle(
6363
color: isSelected
64-
? Colors.white
65-
: Colors.black.withValues(alpha: 0.5),
64+
? appearance.ratingButtonSelectedTextColor
65+
: appearance.ratingButtonUnselectedTextColor,
6666
fontSize: 16,
6767
fontWeight: FontWeight.bold,
6868
),
@@ -78,7 +78,7 @@ class NumberRatingButton extends StatelessWidget {
7878
Container(
7979
height: 45,
8080
width: 1,
81-
color: appearance.borderColor ?? Colors.grey.shade400,
81+
color: appearance.borderColor,
8282
),
8383
],
8484
),

lib/src/surveys/widgets/open_text_question.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ class _OpenTextQuestionState extends State<OpenTextQuestion> {
6666
minHeight: 80,
6767
),
6868
decoration: BoxDecoration(
69-
color: Colors.white,
70-
border: Border.all(color: Colors.grey.shade400),
69+
color: widget.appearance.inputBackgroundColor,
70+
border: Border.all(color: widget.appearance.borderColor),
7171
borderRadius: BorderRadius.circular(6),
7272
),
7373
child: SingleChildScrollView(
@@ -77,10 +77,12 @@ class _OpenTextQuestionState extends State<OpenTextQuestion> {
7777
textAlignVertical: TextAlignVertical.top,
7878
decoration: InputDecoration(
7979
hintText: 'Start typing...',
80-
hintStyle: TextStyle(color: Colors.grey.shade600),
80+
hintStyle: TextStyle(
81+
color: widget.appearance.inputPlaceholderColor),
8182
contentPadding: const EdgeInsets.all(12),
8283
border: InputBorder.none,
8384
),
85+
style: TextStyle(color: widget.appearance.inputTextColor),
8486
onChanged: (value) {
8587
setState(() {
8688
_response = value;

0 commit comments

Comments
 (0)