From e3ce6e8b4bcd598b450ccbfb8f16a761f981121f Mon Sep 17 00:00:00 2001 From: Morn Date: Mon, 20 Jan 2025 17:54:26 +0800 Subject: [PATCH] fix: use WindowSizeManager to zoom on mobile (#7215) --- .../mobile/settings/scale_factor_test.dart | 48 +++++++++++++ .../integration_test/shared/base.dart | 20 ++++++ .../appearance/text_scale_setting.dart | 72 +++++++++++++------ 3 files changed, 120 insertions(+), 20 deletions(-) create mode 100644 frontend/appflowy_flutter/integration_test/mobile/settings/scale_factor_test.dart diff --git a/frontend/appflowy_flutter/integration_test/mobile/settings/scale_factor_test.dart b/frontend/appflowy_flutter/integration_test/mobile/settings/scale_factor_test.dart new file mode 100644 index 0000000000..908caa89d5 --- /dev/null +++ b/frontend/appflowy_flutter/integration_test/mobile/settings/scale_factor_test.dart @@ -0,0 +1,48 @@ +import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/mobile/presentation/home/setting/settings_popup_menu.dart'; +import 'package:appflowy/workspace/presentation/home/hotkeys.dart'; +import 'package:appflowy/workspace/presentation/widgets/more_view_actions/widgets/font_size_stepper.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import '../../shared/util.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('test for change scale factor', (tester) async { + await tester.launchInAnonymousMode(); + + /// tap [Setting] button + await tester.tapButton(find.byType(HomePageSettingsPopupMenu)); + await tester + .tapButton(find.text(LocaleKeys.settings_popupMenuItem_settings.tr())); + + /// tap [Font Scale Factor] + await tester.tapButton( + find.text(LocaleKeys.settings_appearance_fontScaleFactor.tr()), + ); + + /// drag slider + final slider = find.descendant( + of: find.byType(FontSizeStepper), + matching: find.byType(Slider), + ); + await tester.slideToValue(slider, 0.8); + expect(appflowyScaleFactor, 0.8); + + await tester.slideToValue(slider, 0.9); + expect(appflowyScaleFactor, 0.9); + + await tester.slideToValue(slider, 1.0); + expect(appflowyScaleFactor, 1.0); + + await tester.slideToValue(slider, 1.1); + expect(appflowyScaleFactor, 1.1); + + await tester.slideToValue(slider, 1.2); + expect(appflowyScaleFactor, 1.2); + }); +} diff --git a/frontend/appflowy_flutter/integration_test/shared/base.dart b/frontend/appflowy_flutter/integration_test/shared/base.dart index 4a7ec9081f..493cb4c1f0 100644 --- a/frontend/appflowy_flutter/integration_test/shared/base.dart +++ b/frontend/appflowy_flutter/integration_test/shared/base.dart @@ -13,6 +13,7 @@ import 'package:appflowy/workspace/application/settings/prelude.dart'; import 'package:flowy_infra/uuid.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:path/path.dart' as p; @@ -235,6 +236,25 @@ extension AppFlowyTestBase on WidgetTester { Future wait(int milliseconds) async { await pumpAndSettle(Duration(milliseconds: milliseconds)); } + + Future slideToValue( + Finder slider, + double value, { + double paddingOffset = 24.0, + }) async { + final sliderWidget = slider.evaluate().first.widget as Slider; + final range = sliderWidget.max - sliderWidget.min; + final initialRate = (value - sliderWidget.min) / range; + final totalWidth = getSize(slider).width - (2 * paddingOffset); + final zeroPoint = getTopLeft(slider) + + Offset( + paddingOffset + initialRate * totalWidth, + getSize(slider).height / 2, + ); + final calculatedOffset = value * (totalWidth / 100); + await dragFrom(zeroPoint, Offset(calculatedOffset, 0)); + await pumpAndSettle(); + } } extension AppFlowyFinderTestBase on CommonFinders { diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/text_scale_setting.dart b/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/text_scale_setting.dart index 3bdb836a71..00dafb9391 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/text_scale_setting.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/text_scale_setting.dart @@ -1,39 +1,55 @@ -import 'package:flutter/material.dart'; - import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; -import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart'; +import 'package:appflowy/startup/startup.dart'; +import 'package:appflowy/startup/tasks/app_window_size_manager.dart'; +import 'package:appflowy/workspace/presentation/home/hotkeys.dart'; import 'package:appflowy/workspace/presentation/widgets/more_view_actions/widgets/font_size_stepper.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter/material.dart'; +import 'package:scaled_app/scaled_app.dart'; import '../setting.dart'; const int _divisions = 4; +const double _minMobileScaleFactor = 0.8; +const double _maxMobileScaleFactor = 1.2; -class TextScaleSetting extends StatelessWidget { +class TextScaleSetting extends StatefulWidget { const TextScaleSetting({ super.key, }); + @override + State createState() => _TextScaleSettingState(); +} + +class _TextScaleSettingState extends State { + double scaleFactor = 1.0; + final windowSizeManager = WindowSizeManager(); + + @override + void initState() { + super.initState(); + windowSizeManager.getScaleFactor().then((v) { + if (v != scaleFactor && mounted) { + setState(() { + scaleFactor = v; + }); + } + }); + } + @override Widget build(BuildContext context) { final theme = Theme.of(context); - final textScaleFactor = - context.watch().state.textScaleFactor; return MobileSettingItem( name: LocaleKeys.settings_appearance_fontScaleFactor.tr(), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ FlowyText( - // map the text scale factor to the 0-1 - // 0.8 - 0.0 - // 0.9 - 0.5 - // 1.0 - 1.0 - ((_divisions + 1) * textScaleFactor - _divisions) - .toStringAsFixed(2), + scaleFactor.toStringAsFixed(2), color: theme.colorScheme.onSurface, ), const Icon(Icons.chevron_right), @@ -48,14 +64,12 @@ class TextScaleSetting extends StatelessWidget { title: LocaleKeys.settings_appearance_fontScaleFactor.tr(), builder: (context) { return FontSizeStepper( - value: textScaleFactor, - minimumValue: 0.8, - maximumValue: 1.0, + value: scaleFactor, + minimumValue: _minMobileScaleFactor, + maximumValue: _maxMobileScaleFactor, divisions: _divisions, - onChanged: (newTextScaleFactor) { - context - .read() - .setTextScaleFactor(newTextScaleFactor); + onChanged: (newScaleFactor) async { + await _setScale(newScaleFactor); }, ); }, @@ -63,4 +77,22 @@ class TextScaleSetting extends StatelessWidget { }, ); } + + Future _setScale(double value) async { + if (FlowyRunner.currentMode == IntegrationMode.integrationTest) { + // The integration test will fail if we check the scale factor in the test. + // #0 ScaledWidgetsFlutterBinding.Eval () + // #1 ScaledWidgetsFlutterBinding.instance (package:scaled_app/scaled_app.dart:66:62) + // ignore: invalid_use_of_visible_for_testing_member + appflowyScaleFactor = value; + } else { + ScaledWidgetsFlutterBinding.instance.scaleFactor = (_) => value; + } + if (mounted) { + setState(() { + scaleFactor = value; + }); + } + await windowSizeManager.setScaleFactor(value); + } }