Skip to content
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
115 changes: 27 additions & 88 deletions lib/features/settings/presentation/settings_drawer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import '../../updates/presentation/update_view_model.dart';
import '../domain/app_settings.dart';
import '../domain/login_item_status.dart';
import 'settings_view_model.dart';
import 'widgets/compact_settings_item.dart';
import 'widgets/compact_settings_toggle.dart';
import 'widgets/update_settings_section.dart';

Expand Down Expand Up @@ -164,17 +165,20 @@ class _AlwaysOnTopSetting extends StatelessWidget {
@override
Widget build(BuildContext context) {
final enabled = !viewModel.isSaving;
return _SettingsToggleRow(
settingKey: const Key('always-on-top-setting'),
toggleKey: const Key('always-on-top-toggle'),
return CompactSettingsItem(
key: const Key('always-on-top-setting'),
label: context.l10n.alwaysOnTopLabel,
value: viewModel.alwaysOnTop,
enabled: enabled,
onTap: enabled
toggled: viewModel.alwaysOnTop,
onPressed: enabled
? () {
unawaited(viewModel.setAlwaysOnTop(!viewModel.alwaysOnTop));
}
: null,
trailing: CompactSettingsToggle(
key: const Key('always-on-top-toggle'),
value: viewModel.alwaysOnTop,
enabled: enabled,
),
);
}
}
Expand All @@ -187,17 +191,20 @@ class _OpenAtLoginSetting extends StatelessWidget {
@override
Widget build(BuildContext context) {
final enabled = viewModel.canChangeOpenAtLogin;
return _SettingsToggleRow(
settingKey: const Key('open-at-login-setting'),
toggleKey: const Key('open-at-login-toggle'),
return CompactSettingsItem(
key: const Key('open-at-login-setting'),
label: context.l10n.openAtLoginLabel,
value: viewModel.openAtLogin,
enabled: enabled,
onTap: enabled
toggled: viewModel.openAtLogin,
onPressed: enabled
? () {
unawaited(viewModel.setOpenAtLogin(!viewModel.openAtLogin));
}
: null,
trailing: CompactSettingsToggle(
key: const Key('open-at-login-toggle'),
value: viewModel.openAtLogin,
enabled: enabled,
),
);
}
}
Expand All @@ -210,13 +217,11 @@ class _CollapseWhenClickingOutsideSetting extends StatelessWidget {
@override
Widget build(BuildContext context) {
final enabled = !viewModel.isSaving;
return _SettingsToggleRow(
settingKey: const Key('collapse-when-clicking-outside-setting'),
toggleKey: const Key('collapse-when-clicking-outside-toggle'),
return CompactSettingsItem(
key: const Key('collapse-when-clicking-outside-setting'),
label: context.l10n.collapseWhenClickingOutsideLabel,
value: viewModel.collapseWhenClickingOutside,
enabled: enabled,
onTap: enabled
toggled: viewModel.collapseWhenClickingOutside,
onPressed: enabled
? () {
unawaited(
viewModel.setCollapseWhenClickingOutside(
Expand All @@ -225,76 +230,10 @@ class _CollapseWhenClickingOutsideSetting extends StatelessWidget {
);
}
: null,
);
}
}

class _SettingsToggleRow extends StatelessWidget {
const _SettingsToggleRow({
required this.settingKey,
required this.toggleKey,
required this.label,
required this.value,
required this.enabled,
required this.onTap,
});

final Key settingKey;
final Key toggleKey;
final String label;
final bool value;
final bool enabled;
final VoidCallback? onTap;

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Semantics(
label: label,
toggled: value,
enabled: enabled,
child: ExcludeSemantics(
child: Material(
color: Colors.transparent,
child: InkWell(
key: settingKey,
borderRadius: BorderRadius.circular(8),
hoverColor: theme.colorScheme.primary.withValues(alpha: 0.06),
highlightColor: theme.colorScheme.primary.withValues(alpha: 0.10),
onTap: onTap,
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 34),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Row(
children: <Widget>[
Expanded(
child: Text(
label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodyMedium?.copyWith(
color: enabled
? null
: theme.colorScheme.onSurface.withValues(
alpha: 0.38,
),
fontWeight: FontWeight.w500,
),
),
),
const SizedBox(width: 12),
CompactSettingsToggle(
key: toggleKey,
value: value,
enabled: enabled,
),
],
),
),
),
),
),
trailing: CompactSettingsToggle(
key: const Key('collapse-when-clicking-outside-toggle'),
value: viewModel.collapseWhenClickingOutside,
enabled: enabled,
),
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import 'package:flutter/material.dart';

const _compactSettingsItemMinHeight = 34.0;
const _compactSettingsItemRadius = 8.0;
const _compactSettingsItemLabelFontSize = 11.0;

class CompactSettingsItem extends StatelessWidget {
const CompactSettingsItem({
required this.label,
required this.trailing,
required this.onPressed,
this.toggled,
super.key,
});

final String label;
final Widget trailing;
final VoidCallback? onPressed;
final bool? toggled;

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final enabled = onPressed != null;

return Semantics(
button: toggled == null,
enabled: enabled,
label: label,
toggled: toggled,
child: ExcludeSemantics(
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(_compactSettingsItemRadius),
hoverColor: theme.colorScheme.primary.withValues(alpha: 0.06),
highlightColor: theme.colorScheme.primary.withValues(alpha: 0.10),
onTap: onPressed,
child: ConstrainedBox(
constraints: const BoxConstraints(
minHeight: _compactSettingsItemMinHeight,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
child: Row(
children: <Widget>[
Expanded(
child: Text(
label,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.labelSmall?.copyWith(
color: enabled
? theme.colorScheme.onSurface
: theme.colorScheme.onSurface.withValues(
alpha: 0.38,
),
fontSize: _compactSettingsItemLabelFontSize,
fontWeight: FontWeight.w500,
height: 1.2,
),
),
),
const SizedBox(width: 12),
trailing,
],
),
),
),
),
),
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import 'package:flutter/material.dart';

import '../../../../l10n/l10n.dart';
import '../../../updates/presentation/update_view_model.dart';
import 'compact_settings_item.dart';
import 'compact_settings_toggle.dart';

const _updateRowHeight = 34.0;
const _updateRowRadius = 8.0;

class UpdateSettingsSection extends StatelessWidget {
const UpdateSettingsSection({required this.viewModel, super.key});

Expand Down Expand Up @@ -59,7 +57,7 @@ class UpdateSettingsSection extends StatelessWidget {
],
),
const SizedBox(height: 6),
_UpdateSettingRow(
CompactSettingsItem(
key: const Key('automatic-update-checks'),
label: localizations.automaticUpdateChecksLabel,
toggled: viewModel.automaticallyChecksForUpdates,
Expand All @@ -79,7 +77,7 @@ class UpdateSettingsSection extends StatelessWidget {
),
),
const SizedBox(height: 2),
_UpdateSettingRow(
CompactSettingsItem(
key: const Key('check-for-updates'),
onPressed: viewModel.isLoading || viewModel.isChecking
? null
Expand Down Expand Up @@ -118,71 +116,6 @@ class UpdateSettingsSection extends StatelessWidget {
}
}

class _UpdateSettingRow extends StatelessWidget {
const _UpdateSettingRow({
required this.label,
required this.trailing,
required this.onPressed,
this.toggled,
super.key,
});

final String label;
final Widget trailing;
final VoidCallback? onPressed;
final bool? toggled;

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);

return Semantics(
button: toggled == null,
enabled: onPressed != null,
label: label,
toggled: toggled,
child: ExcludeSemantics(
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(_updateRowRadius),
hoverColor: theme.colorScheme.primary.withValues(alpha: 0.06),
highlightColor: theme.colorScheme.primary.withValues(alpha: 0.10),
onTap: onPressed,
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: _updateRowHeight),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Row(
children: <Widget>[
Expanded(
child: Text(
label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodyMedium?.copyWith(
color: onPressed == null
? theme.colorScheme.onSurface.withValues(
alpha: 0.38,
)
: null,
fontWeight: FontWeight.w500,
),
),
),
const SizedBox(width: 12),
trailing,
],
),
),
),
),
),
),
);
}
}

class _UpdateStatus extends StatelessWidget {
const _UpdateStatus({
required this.message,
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: floatick
description: A focused, local-first floating todo list for macOS.
publish_to: 'none'
version: 0.3.0+7
version: 0.3.1+8

environment:
sdk: ^3.12.2
Expand Down
10 changes: 10 additions & 0 deletions test/app/floatick_app_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,16 @@ void main() {
expect(find.text('每天检查一次,安装前会询问你'), findsNothing);
expect(find.text('自动检查'), findsOneWidget);
expect(find.text('立即检查'), findsOneWidget);
final collapseWhenClickingOutsideText = tester.widget<Text>(
find.text('点击外部时收起'),
);
expect(collapseWhenClickingOutsideText.maxLines, 2);
expect(collapseWhenClickingOutsideText.overflow, TextOverflow.ellipsis);
expect(collapseWhenClickingOutsideText.style?.fontSize, 11);
final automaticUpdateChecksText = tester.widget<Text>(find.text('自动检查'));
expect(automaticUpdateChecksText.maxLines, 2);
expect(automaticUpdateChecksText.overflow, TextOverflow.ellipsis);
expect(automaticUpdateChecksText.style?.fontSize, 11);
expect(find.byType(Switch), findsNothing);
expect(
tester.getSize(find.byKey(const Key('automatic-update-toggle'))),
Expand Down
Loading