Showing
9 changed files
with
88 additions
and
56 deletions
| @@ -169,6 +169,8 @@ class FriendsController extends GetxController { | @@ -169,6 +169,8 @@ class FriendsController extends GetxController { | ||
| 169 | _friendListVersion != pendingOrder.listVersion) { | 169 | _friendListVersion != pendingOrder.listVersion) { |
| 170 | unawaited(refreshData()); | 170 | unawaited(refreshData()); |
| 171 | } | 171 | } |
| 172 | + ta.track('ita_doublefeel_friend_page', | ||
| 173 | + properties: {'ita_content': '长按拖动卡片'}); | ||
| 172 | } catch (error, stackTrace) { | 174 | } catch (error, stackTrace) { |
| 173 | AppLogger.e( | 175 | AppLogger.e( |
| 174 | 'FriendsController.reorderFriends failed', | 176 | 'FriendsController.reorderFriends failed', |
| @@ -250,6 +252,7 @@ class FriendsController extends GetxController { | @@ -250,6 +252,7 @@ class FriendsController extends GetxController { | ||
| 250 | markName: selectedFriend.remark, | 252 | markName: selectedFriend.remark, |
| 251 | ), | 253 | ), |
| 252 | ); | 254 | ); |
| 255 | + ta.track('success_set_doublefeel_friend_on_watch'); | ||
| 253 | } catch (error, stackTrace) { | 256 | } catch (error, stackTrace) { |
| 254 | await loadFriends(); | 257 | await loadFriends(); |
| 255 | if (error is AppError) { | 258 | if (error is AppError) { |
| @@ -66,6 +66,7 @@ class PrivacySettingsView extends GetView<PrivacySettingsController> { | @@ -66,6 +66,7 @@ class PrivacySettingsView extends GetView<PrivacySettingsController> { | ||
| 66 | return _settingRow( | 66 | return _settingRow( |
| 67 | title: context.l10n.privacySettingsDisableAddById, | 67 | title: context.l10n.privacySettingsDisableAddById, |
| 68 | value: controller.disableAddWithUCode, | 68 | value: controller.disableAddWithUCode, |
| 69 | + height: 56.dp, | ||
| 69 | onChanged: () => controller.isUpdatingDisableAddWithUCode.value | 70 | onChanged: () => controller.isUpdatingDisableAddWithUCode.value |
| 70 | ? null | 71 | ? null |
| 71 | : controller.updateDisableAddWithUCode, | 72 | : controller.updateDisableAddWithUCode, |
| @@ -122,15 +123,11 @@ class PrivacySettingsView extends GetView<PrivacySettingsController> { | @@ -122,15 +123,11 @@ class PrivacySettingsView extends GetView<PrivacySettingsController> { | ||
| 122 | ], | 123 | ], |
| 123 | const Spacer(), | 124 | const Spacer(), |
| 124 | Obx( | 125 | Obx( |
| 125 | - () => Transform.scale( | ||
| 126 | - scaleX: 52 / 51, | ||
| 127 | - scaleY: 28 / 31, | ||
| 128 | - child: CupertinoSwitch( | ||
| 129 | - value: value.value, | ||
| 130 | - activeTrackColor: AppColors.primary, | ||
| 131 | - inactiveTrackColor: const Color(0xFFE5E5EA), | ||
| 132 | - onChanged: onChanged(), | ||
| 133 | - ), | 126 | + () => CupertinoSwitch( |
| 127 | + value: value.value, | ||
| 128 | + activeTrackColor: AppColors.primary, | ||
| 129 | + inactiveTrackColor: const Color(0xFFE5E5EA), | ||
| 130 | + onChanged: onChanged(), | ||
| 134 | ), | 131 | ), |
| 135 | ), | 132 | ), |
| 136 | ], | 133 | ], |
| 1 | +import 'package:doublefeel_flutter/app/utils/font_utils.dart'; | ||
| 2 | +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; | ||
| 1 | import 'package:flutter/cupertino.dart'; | 3 | import 'package:flutter/cupertino.dart'; |
| 2 | import 'package:flutter/material.dart'; | 4 | import 'package:flutter/material.dart'; |
| 3 | -import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; | ||
| 4 | 5 | ||
| 5 | import '../config/report_date_range_config.dart'; | 6 | import '../config/report_date_range_config.dart'; |
| 6 | import '../models/report_period.dart'; | 7 | import '../models/report_period.dart'; |
| @@ -233,6 +234,8 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | @@ -233,6 +234,8 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | ||
| 233 | late final FixedExtentScrollController _yearController; | 234 | late final FixedExtentScrollController _yearController; |
| 234 | late FixedExtentScrollController _monthController; | 235 | late FixedExtentScrollController _monthController; |
| 235 | late FixedExtentScrollController _dayController; | 236 | late FixedExtentScrollController _dayController; |
| 237 | + int _monthControllerVersion = 0; | ||
| 238 | + int _dayControllerVersion = 0; | ||
| 236 | 239 | ||
| 237 | @override | 240 | @override |
| 238 | void initState() { | 241 | void initState() { |
| @@ -271,6 +274,8 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | @@ -271,6 +274,8 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | ||
| 271 | final lastMonth = _lastSelectableMonth; | 274 | final lastMonth = _lastSelectableMonth; |
| 272 | final firstDay = _firstSelectableDay; | 275 | final firstDay = _firstSelectableDay; |
| 273 | final lastDay = _lastSelectableDay; | 276 | final lastDay = _lastSelectableDay; |
| 277 | + final monthControllerVersion = _monthControllerVersion; | ||
| 278 | + final dayControllerVersion = _dayControllerVersion; | ||
| 274 | final yearPicker = Expanded( | 279 | final yearPicker = Expanded( |
| 275 | child: _picker( | 280 | child: _picker( |
| 276 | controller: _yearController, | 281 | controller: _yearController, |
| @@ -290,6 +295,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | @@ -290,6 +295,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | ||
| 290 | ); | 295 | ); |
| 291 | final monthPicker = Expanded( | 296 | final monthPicker = Expanded( |
| 292 | child: _picker( | 297 | child: _picker( |
| 298 | + key: ValueKey('month-$_monthControllerVersion'), | ||
| 293 | controller: _monthController, | 299 | controller: _monthController, |
| 294 | count: lastMonth - firstMonth + 1, | 300 | count: lastMonth - firstMonth + 1, |
| 295 | selectedIndex: _month - firstMonth, | 301 | selectedIndex: _month - firstMonth, |
| @@ -298,6 +304,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | @@ -298,6 +304,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | ||
| 298 | Localizations.localeOf(context).toLanguageTag(), | 304 | Localizations.localeOf(context).toLanguageTag(), |
| 299 | ), | 305 | ), |
| 300 | onSelectedItemChanged: (index) { | 306 | onSelectedItemChanged: (index) { |
| 307 | + if (monthControllerVersion != _monthControllerVersion) return; | ||
| 301 | setState(() { | 308 | setState(() { |
| 302 | _month = firstMonth + index; | 309 | _month = firstMonth + index; |
| 303 | _clampDay(); | 310 | _clampDay(); |
| @@ -307,6 +314,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | @@ -307,6 +314,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | ||
| 307 | ); | 314 | ); |
| 308 | final dayPicker = Expanded( | 315 | final dayPicker = Expanded( |
| 309 | child: _picker( | 316 | child: _picker( |
| 317 | + key: ValueKey('day-$_dayControllerVersion'), | ||
| 310 | controller: _dayController, | 318 | controller: _dayController, |
| 311 | count: lastDay - firstDay + 1, | 319 | count: lastDay - firstDay + 1, |
| 312 | selectedIndex: _day - firstDay, | 320 | selectedIndex: _day - firstDay, |
| @@ -315,6 +323,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | @@ -315,6 +323,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | ||
| 315 | Localizations.localeOf(context).toLanguageTag(), | 323 | Localizations.localeOf(context).toLanguageTag(), |
| 316 | ), | 324 | ), |
| 317 | onSelectedItemChanged: (index) { | 325 | onSelectedItemChanged: (index) { |
| 326 | + if (dayControllerVersion != _dayControllerVersion) return; | ||
| 318 | setState(() => _day = firstDay + index); | 327 | setState(() => _day = firstDay + index); |
| 319 | }, | 328 | }, |
| 320 | ), | 329 | ), |
| @@ -365,6 +374,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | @@ -365,6 +374,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | ||
| 365 | } | 374 | } |
| 366 | 375 | ||
| 367 | Widget _picker({ | 376 | Widget _picker({ |
| 377 | + Key? key, | ||
| 368 | required FixedExtentScrollController controller, | 378 | required FixedExtentScrollController controller, |
| 369 | required int count, | 379 | required int count, |
| 370 | required int selectedIndex, | 380 | required int selectedIndex, |
| @@ -372,6 +382,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | @@ -372,6 +382,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | ||
| 372 | required ValueChanged<int> onSelectedItemChanged, | 382 | required ValueChanged<int> onSelectedItemChanged, |
| 373 | }) { | 383 | }) { |
| 374 | return CupertinoPicker.builder( | 384 | return CupertinoPicker.builder( |
| 385 | + key: key, | ||
| 375 | scrollController: controller, | 386 | scrollController: controller, |
| 376 | itemExtent: _itemExtent, | 387 | itemExtent: _itemExtent, |
| 377 | diameterRatio: 1.6, | 388 | diameterRatio: 1.6, |
| @@ -424,6 +435,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | @@ -424,6 +435,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | ||
| 424 | final nextMonth = _month.clamp(firstMonth, lastMonth); | 435 | final nextMonth = _month.clamp(firstMonth, lastMonth); |
| 425 | _month = nextMonth; | 436 | _month = nextMonth; |
| 426 | _monthController.dispose(); | 437 | _monthController.dispose(); |
| 438 | + _monthControllerVersion++; | ||
| 427 | _monthController = | 439 | _monthController = |
| 428 | FixedExtentScrollController(initialItem: _month - firstMonth); | 440 | FixedExtentScrollController(initialItem: _month - firstMonth); |
| 429 | _clampDay(); | 441 | _clampDay(); |
| @@ -435,6 +447,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | @@ -435,6 +447,7 @@ class _DayDatePickerSheetState extends State<_DayDatePickerSheet> { | ||
| 435 | final nextDay = _day.clamp(firstDay, lastDay); | 447 | final nextDay = _day.clamp(firstDay, lastDay); |
| 436 | _day = nextDay; | 448 | _day = nextDay; |
| 437 | _dayController.dispose(); | 449 | _dayController.dispose(); |
| 450 | + _dayControllerVersion++; | ||
| 438 | _dayController = FixedExtentScrollController(initialItem: _day - firstDay); | 451 | _dayController = FixedExtentScrollController(initialItem: _day - firstDay); |
| 439 | } | 452 | } |
| 440 | 453 | ||
| @@ -757,7 +770,7 @@ class _AdjacentPicker extends StatelessWidget { | @@ -757,7 +770,7 @@ class _AdjacentPicker extends StatelessWidget { | ||
| 757 | softWrap: false, | 770 | softWrap: false, |
| 758 | overflow: TextOverflow.visible, | 771 | overflow: TextOverflow.visible, |
| 759 | style: TextStyle( | 772 | style: TextStyle( |
| 760 | - fontFamily: 'PingFangSC', | 773 | + fontFamily: FontUtils.getFontFamily(context), |
| 761 | color: selected | 774 | color: selected |
| 762 | ? _ReportPickerColors.h1 | 775 | ? _ReportPickerColors.h1 |
| 763 | : adjacent | 776 | : adjacent |
| 1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
| 2 | 2 | ||
| 3 | +import '../../../utils/font_utils.dart'; | ||
| 4 | + | ||
| 3 | class ReportDateSwitcher extends StatelessWidget { | 5 | class ReportDateSwitcher extends StatelessWidget { |
| 4 | const ReportDateSwitcher({ | 6 | const ReportDateSwitcher({ |
| 5 | super.key, | 7 | super.key, |
| @@ -48,12 +50,12 @@ class ReportDateSwitcher extends StatelessWidget { | @@ -48,12 +50,12 @@ class ReportDateSwitcher extends StatelessWidget { | ||
| 48 | children: [ | 50 | children: [ |
| 49 | Text( | 51 | Text( |
| 50 | label, | 52 | label, |
| 51 | - style: const TextStyle( | 53 | + style: TextStyle( |
| 52 | color: _brand, | 54 | color: _brand, |
| 53 | fontSize: 14, | 55 | fontSize: 14, |
| 54 | fontWeight: FontWeight.w500, | 56 | fontWeight: FontWeight.w500, |
| 55 | height: 1.2, | 57 | height: 1.2, |
| 56 | - fontFamily: 'PingFangSC', | 58 | + fontFamily: FontUtils.getFontFamily(context), |
| 57 | ), | 59 | ), |
| 58 | ), | 60 | ), |
| 59 | const SizedBox(width: 2), | 61 | const SizedBox(width: 2), |
| 1 | -import 'package:flutter/material.dart'; | ||
| 2 | import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; | 1 | import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; |
| 2 | +import 'package:flutter/material.dart'; | ||
| 3 | 3 | ||
| 4 | import 'sleep_report_text_styles.dart'; | 4 | import 'sleep_report_text_styles.dart'; |
| 5 | 5 | ||
| @@ -68,8 +68,9 @@ class SleepQualityDialog extends StatelessWidget { | @@ -68,8 +68,9 @@ class SleepQualityDialog extends StatelessWidget { | ||
| 68 | child: Text( | 68 | child: Text( |
| 69 | context.l10n.sleepQualityTitle, | 69 | context.l10n.sleepQualityTitle, |
| 70 | textAlign: TextAlign.center, | 70 | textAlign: TextAlign.center, |
| 71 | - strutStyle: SleepReportTextStyles.titleStrutStyle, | ||
| 72 | - style: SleepReportTextStyles.titleTextStyle, | 71 | + strutStyle: |
| 72 | + SleepReportTextStyles.titleStrutStyle(context), | ||
| 73 | + style: SleepReportTextStyles.titleTextStyle(context), | ||
| 73 | ), | 74 | ), |
| 74 | ), | 75 | ), |
| 75 | ), | 76 | ), |
| 1 | -import 'package:flutter/foundation.dart'; | 1 | +import 'package:doublefeel_flutter/app/utils/font_utils.dart'; |
| 2 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
| 3 | 3 | ||
| 4 | abstract final class SleepReportTextStyles { | 4 | abstract final class SleepReportTextStyles { |
| 5 | static const titleColor = Color(0xFF0F0F11); | 5 | static const titleColor = Color(0xFF0F0F11); |
| 6 | 6 | ||
| 7 | - static bool get _usesAppleTextRenderer => | ||
| 8 | - defaultTargetPlatform == TargetPlatform.iOS || | ||
| 9 | - defaultTargetPlatform == TargetPlatform.macOS; | ||
| 10 | - | ||
| 11 | - static TextStyle get titleTextStyle { | ||
| 12 | - const baseStyle = TextStyle( | 7 | + static TextStyle titleTextStyle(BuildContext context) { |
| 8 | + final fontFamily = FontUtils.getFontFamily(context); | ||
| 9 | + return TextStyle( | ||
| 13 | color: titleColor, | 10 | color: titleColor, |
| 14 | fontSize: 16, | 11 | fontSize: 16, |
| 15 | fontWeight: FontWeight.w600, | 12 | fontWeight: FontWeight.w600, |
| 16 | height: 1.2, | 13 | height: 1.2, |
| 17 | - ); | ||
| 18 | - if (!_usesAppleTextRenderer) return baseStyle; | ||
| 19 | - return baseStyle.copyWith( | ||
| 20 | - fontFamily: 'PingFangSC', | ||
| 21 | - fontFamilyFallback: const ['Heiti SC', 'Arial Unicode MS'], | 14 | + fontFamily: fontFamily, |
| 22 | ); | 15 | ); |
| 23 | } | 16 | } |
| 24 | 17 | ||
| 25 | - static StrutStyle get titleStrutStyle { | ||
| 26 | - if (!_usesAppleTextRenderer) { | ||
| 27 | - return const StrutStyle( | ||
| 28 | - fontSize: 16, | ||
| 29 | - height: 1.2, | ||
| 30 | - ); | ||
| 31 | - } | ||
| 32 | - return const StrutStyle( | 18 | + static StrutStyle titleStrutStyle(BuildContext context) { |
| 19 | + final fontFamily = FontUtils.getFontFamily(context); | ||
| 20 | + return StrutStyle( | ||
| 33 | fontSize: 16, | 21 | fontSize: 16, |
| 34 | - fontFamily: 'PingFangSC', | ||
| 35 | - fontFamilyFallback: ['Heiti SC', 'Arial Unicode MS'], | ||
| 36 | height: 1.2, | 22 | height: 1.2, |
| 23 | + fontFamily: fontFamily, | ||
| 37 | ); | 24 | ); |
| 38 | } | 25 | } |
| 39 | } | 26 | } |
| @@ -34,10 +34,11 @@ class SleepWeekReportView extends StatelessWidget { | @@ -34,10 +34,11 @@ class SleepWeekReportView extends StatelessWidget { | ||
| 34 | static const h3 = Color(0xFFB0B0B6); | 34 | static const h3 = Color(0xFFB0B0B6); |
| 35 | static const grid = Color(0xFFF3F3F3); | 35 | static const grid = Color(0xFFF3F3F3); |
| 36 | 36 | ||
| 37 | - static TextStyle get titleTextStyle => SleepReportTextStyles.titleTextStyle; | 37 | + static TextStyle titleTextStyle(BuildContext context) => |
| 38 | + SleepReportTextStyles.titleTextStyle(context); | ||
| 38 | 39 | ||
| 39 | - static StrutStyle get titleStrutStyle => | ||
| 40 | - SleepReportTextStyles.titleStrutStyle; | 40 | + static StrutStyle titleStrutStyle(BuildContext context) => |
| 41 | + SleepReportTextStyles.titleStrutStyle(context); | ||
| 41 | 42 | ||
| 42 | static int minutesFromEvening(DateTime time) { | 43 | static int minutesFromEvening(DateTime time) { |
| 43 | final minutes = time.hour * 60 + time.minute; | 44 | final minutes = time.hour * 60 + time.minute; |
| @@ -463,8 +464,8 @@ class _TrendCard extends StatelessWidget { | @@ -463,8 +464,8 @@ class _TrendCard extends StatelessWidget { | ||
| 463 | children: [ | 464 | children: [ |
| 464 | Text( | 465 | Text( |
| 465 | title, | 466 | title, |
| 466 | - strutStyle: SleepWeekReportView.titleStrutStyle, | ||
| 467 | - style: SleepWeekReportView.titleTextStyle, | 467 | + strutStyle: SleepWeekReportView.titleStrutStyle(context), |
| 468 | + style: SleepWeekReportView.titleTextStyle(context), | ||
| 468 | ), | 469 | ), |
| 469 | const SizedBox(height: 14), | 470 | const SizedBox(height: 14), |
| 470 | Expanded(child: chart), | 471 | Expanded(child: chart), |
| @@ -616,6 +617,7 @@ class _DurationChartState extends State<_DurationChart> { | @@ -616,6 +617,7 @@ class _DurationChartState extends State<_DurationChart> { | ||
| 616 | widget.compact, | 617 | widget.compact, |
| 617 | ), | 618 | ), |
| 618 | barTouchData: _barTouchData( | 619 | barTouchData: _barTouchData( |
| 620 | + context: context, | ||
| 619 | days: widget.days, | 621 | days: widget.days, |
| 620 | chartWidth: plotWidth, | 622 | chartWidth: plotWidth, |
| 621 | compact: widget.compact, | 623 | compact: widget.compact, |
| @@ -823,6 +825,7 @@ class _QualityChartState extends State<_QualityChart> { | @@ -823,6 +825,7 @@ class _QualityChartState extends State<_QualityChart> { | ||
| 823 | widget.compact, | 825 | widget.compact, |
| 824 | ), | 826 | ), |
| 825 | barTouchData: _barTouchData( | 827 | barTouchData: _barTouchData( |
| 828 | + context: context, | ||
| 826 | days: widget.days, | 829 | days: widget.days, |
| 827 | chartWidth: plotWidth, | 830 | chartWidth: plotWidth, |
| 828 | compact: widget.compact, | 831 | compact: widget.compact, |
| @@ -1107,6 +1110,7 @@ class _BedtimeChartState extends State<_BedtimeChart> { | @@ -1107,6 +1110,7 @@ class _BedtimeChartState extends State<_BedtimeChart> { | ||
| 1107 | handleBuiltInTouches: false, | 1110 | handleBuiltInTouches: false, |
| 1108 | getTouchedSpotIndicator: _lineTouchedIndicators, | 1111 | getTouchedSpotIndicator: _lineTouchedIndicators, |
| 1109 | touchTooltipData: _lineTooltipData( | 1112 | touchTooltipData: _lineTooltipData( |
| 1113 | + context: context, | ||
| 1110 | days: widget.days, | 1114 | days: widget.days, |
| 1111 | dataBuilder: (report) => _ChartSummaryData.bedtime( | 1115 | dataBuilder: (report) => _ChartSummaryData.bedtime( |
| 1112 | report, | 1116 | report, |
| @@ -1292,6 +1296,7 @@ class _BedtimeAxis { | @@ -1292,6 +1296,7 @@ class _BedtimeAxis { | ||
| 1292 | } | 1296 | } |
| 1293 | 1297 | ||
| 1294 | BarTouchData _barTouchData({ | 1298 | BarTouchData _barTouchData({ |
| 1299 | + required BuildContext context, | ||
| 1295 | required List<SleepReport> days, | 1300 | required List<SleepReport> days, |
| 1296 | required double chartWidth, | 1301 | required double chartWidth, |
| 1297 | required bool compact, | 1302 | required bool compact, |
| @@ -1350,7 +1355,7 @@ BarTouchData _barTouchData({ | @@ -1350,7 +1355,7 @@ BarTouchData _barTouchData({ | ||
| 1350 | if (groupIndex < 0 || groupIndex >= days.length) return null; | 1355 | if (groupIndex < 0 || groupIndex >= days.length) return null; |
| 1351 | final report = days[groupIndex]; | 1356 | final report = days[groupIndex]; |
| 1352 | if (!hasData(report)) return null; | 1357 | if (!hasData(report)) return null; |
| 1353 | - return _barTooltipItem(dataBuilder(report)); | 1358 | + return _barTooltipItem(context, dataBuilder(report)); |
| 1354 | }, | 1359 | }, |
| 1355 | ), | 1360 | ), |
| 1356 | ); | 1361 | ); |
| @@ -1390,10 +1395,12 @@ double _barCenterForIndex( | @@ -1390,10 +1395,12 @@ double _barCenterForIndex( | ||
| 1390 | return chartLeft + barWidth / 2 + (barWidth + groupsSpace) * index; | 1395 | return chartLeft + barWidth / 2 + (barWidth + groupsSpace) * index; |
| 1391 | } | 1396 | } |
| 1392 | 1397 | ||
| 1393 | -BarTooltipItem _barTooltipItem(_ChartSummaryData data) { | 1398 | +BarTooltipItem _barTooltipItem(BuildContext context, _ChartSummaryData data) { |
| 1394 | return BarTooltipItem( | 1399 | return BarTooltipItem( |
| 1395 | data.title, | 1400 | data.title, |
| 1396 | - SleepWeekReportView.titleTextStyle.copyWith(color: data.titleColor), | 1401 | + SleepWeekReportView.titleTextStyle(context).copyWith( |
| 1402 | + color: data.titleColor, | ||
| 1403 | + ), | ||
| 1397 | textAlign: TextAlign.start, | 1404 | textAlign: TextAlign.start, |
| 1398 | children: [ | 1405 | children: [ |
| 1399 | TextSpan( | 1406 | TextSpan( |
| @@ -1410,6 +1417,7 @@ BarTooltipItem _barTooltipItem(_ChartSummaryData data) { | @@ -1410,6 +1417,7 @@ BarTooltipItem _barTooltipItem(_ChartSummaryData data) { | ||
| 1410 | } | 1417 | } |
| 1411 | 1418 | ||
| 1412 | LineTouchTooltipData _lineTooltipData({ | 1419 | LineTouchTooltipData _lineTooltipData({ |
| 1420 | + required BuildContext context, | ||
| 1413 | required List<SleepReport> days, | 1421 | required List<SleepReport> days, |
| 1414 | required _ChartSummaryData Function(SleepReport report) dataBuilder, | 1422 | required _ChartSummaryData Function(SleepReport report) dataBuilder, |
| 1415 | }) { | 1423 | }) { |
| @@ -1430,16 +1438,18 @@ LineTouchTooltipData _lineTooltipData({ | @@ -1430,16 +1438,18 @@ LineTouchTooltipData _lineTooltipData({ | ||
| 1430 | if (!report.hasSleepData || report.heartRate.sleepStart == null) { | 1438 | if (!report.hasSleepData || report.heartRate.sleepStart == null) { |
| 1431 | return null; | 1439 | return null; |
| 1432 | } | 1440 | } |
| 1433 | - return _lineTooltipItem(dataBuilder(report)); | 1441 | + return _lineTooltipItem(context, dataBuilder(report)); |
| 1434 | }).toList(); | 1442 | }).toList(); |
| 1435 | }, | 1443 | }, |
| 1436 | ); | 1444 | ); |
| 1437 | } | 1445 | } |
| 1438 | 1446 | ||
| 1439 | -LineTooltipItem _lineTooltipItem(_ChartSummaryData data) { | 1447 | +LineTooltipItem _lineTooltipItem(BuildContext context, _ChartSummaryData data) { |
| 1440 | return LineTooltipItem( | 1448 | return LineTooltipItem( |
| 1441 | data.title, | 1449 | data.title, |
| 1442 | - SleepWeekReportView.titleTextStyle.copyWith(color: data.titleColor), | 1450 | + SleepWeekReportView.titleTextStyle(context).copyWith( |
| 1451 | + color: data.titleColor, | ||
| 1452 | + ), | ||
| 1443 | textAlign: TextAlign.start, | 1453 | textAlign: TextAlign.start, |
| 1444 | children: [ | 1454 | children: [ |
| 1445 | TextSpan( | 1455 | TextSpan( |
lib/app/utils/font_utils.dart
0 → 100644
| 1 | +import 'package:flutter/widgets.dart'; | ||
| 2 | + | ||
| 3 | +/// Provides locale-aware font selection for text widgets. | ||
| 4 | +class FontUtils { | ||
| 5 | + FontUtils._(); | ||
| 6 | + | ||
| 7 | + static const pingFangSc = 'PingFangSC'; | ||
| 8 | + | ||
| 9 | + /// Returns PingFang SC for Chinese and English; other languages use the | ||
| 10 | + /// platform's default font. | ||
| 11 | + static String? getFontFamily(BuildContext context) { | ||
| 12 | + return getFontFamilyForLocale(Localizations.localeOf(context)); | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + static String? getFontFamilyForLocale(Locale locale) { | ||
| 16 | + switch (locale.languageCode.toLowerCase()) { | ||
| 17 | + case 'zh': | ||
| 18 | + case 'en': | ||
| 19 | + return pingFangSc; | ||
| 20 | + default: | ||
| 21 | + return null; | ||
| 22 | + } | ||
| 23 | + } | ||
| 24 | +} |
| 1 | -import 'package:flutter/foundation.dart'; | ||
| 2 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
| 3 | import 'package:flutter/services.dart'; | 2 | import 'package:flutter/services.dart'; |
| 3 | + | ||
| 4 | import 'app_colors_extension.dart'; | 4 | import 'app_colors_extension.dart'; |
| 5 | 5 | ||
| 6 | /// Class managing the Application ThemeData for both Light and Dark themes. | 6 | /// Class managing the Application ThemeData for both Light and Dark themes. |
| 7 | /// Automatically hooks up our custom Figma colors system as a ThemeExtension. | 7 | /// Automatically hooks up our custom Figma colors system as a ThemeExtension. |
| 8 | class AppTheme { | 8 | class AppTheme { |
| 9 | AppTheme._(); | 9 | AppTheme._(); |
| 10 | - static String? get _platformFontFamily => | ||
| 11 | - defaultTargetPlatform == TargetPlatform.iOS ? 'PingFangSC' : null; | ||
| 12 | 10 | ||
| 13 | static const systemUiOverlayStyle = SystemUiOverlayStyle( | 11 | static const systemUiOverlayStyle = SystemUiOverlayStyle( |
| 14 | statusBarColor: Colors.transparent, | 12 | statusBarColor: Colors.transparent, |
| @@ -24,7 +22,6 @@ class AppTheme { | @@ -24,7 +22,6 @@ class AppTheme { | ||
| 24 | 22 | ||
| 25 | return ThemeData( | 23 | return ThemeData( |
| 26 | useMaterial3: true, | 24 | useMaterial3: true, |
| 27 | - fontFamily: _platformFontFamily, | ||
| 28 | brightness: Brightness.light, | 25 | brightness: Brightness.light, |
| 29 | primaryColor: colors.primary, | 26 | primaryColor: colors.primary, |
| 30 | scaffoldBackgroundColor: colors.backgroundPage, | 27 | scaffoldBackgroundColor: colors.backgroundPage, |
| @@ -39,7 +36,6 @@ class AppTheme { | @@ -39,7 +36,6 @@ class AppTheme { | ||
| 39 | iconTheme: IconThemeData(color: colors.textPrimary), | 36 | iconTheme: IconThemeData(color: colors.textPrimary), |
| 40 | actionsIconTheme: IconThemeData(color: colors.textPrimary), | 37 | actionsIconTheme: IconThemeData(color: colors.textPrimary), |
| 41 | titleTextStyle: TextStyle( | 38 | titleTextStyle: TextStyle( |
| 42 | - fontFamily: _platformFontFamily, | ||
| 43 | color: Colors.black, | 39 | color: Colors.black, |
| 44 | fontSize: 16, | 40 | fontSize: 16, |
| 45 | fontWeight: FontWeight.w500, | 41 | fontWeight: FontWeight.w500, |
| @@ -70,7 +66,6 @@ class AppTheme { | @@ -70,7 +66,6 @@ class AppTheme { | ||
| 70 | final colors = AppColorsExtension.dark(); | 66 | final colors = AppColorsExtension.dark(); |
| 71 | return ThemeData( | 67 | return ThemeData( |
| 72 | useMaterial3: true, | 68 | useMaterial3: true, |
| 73 | - fontFamily: _platformFontFamily, | ||
| 74 | brightness: Brightness.dark, | 69 | brightness: Brightness.dark, |
| 75 | primaryColor: colors.primary, | 70 | primaryColor: colors.primary, |
| 76 | scaffoldBackgroundColor: colors.backgroundLight, | 71 | scaffoldBackgroundColor: colors.backgroundLight, |
| @@ -83,7 +78,6 @@ class AppTheme { | @@ -83,7 +78,6 @@ class AppTheme { | ||
| 83 | iconTheme: IconThemeData(color: colors.textPrimary), | 78 | iconTheme: IconThemeData(color: colors.textPrimary), |
| 84 | actionsIconTheme: IconThemeData(color: colors.textPrimary), | 79 | actionsIconTheme: IconThemeData(color: colors.textPrimary), |
| 85 | titleTextStyle: TextStyle( | 80 | titleTextStyle: TextStyle( |
| 86 | - fontFamily: _platformFontFamily, | ||
| 87 | color: Colors.black, | 81 | color: Colors.black, |
| 88 | fontSize: 16, | 82 | fontSize: 16, |
| 89 | fontWeight: FontWeight.w500, | 83 | fontWeight: FontWeight.w500, |
| @@ -111,5 +105,6 @@ class AppTheme { | @@ -111,5 +105,6 @@ class AppTheme { | ||
| 111 | extension AppThemeContextExtension on BuildContext { | 105 | extension AppThemeContextExtension on BuildContext { |
| 112 | AppColorsExtension get colors => | 106 | AppColorsExtension get colors => |
| 113 | Theme.of(this).extension<AppColorsExtension>()!; | 107 | Theme.of(this).extension<AppColorsExtension>()!; |
| 108 | + | ||
| 114 | ThemeData get theme => Theme.of(this); | 109 | ThemeData get theme => Theme.of(this); |
| 115 | } | 110 | } |
-
Please register or login to post a comment