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
1 change: 1 addition & 0 deletions assets/i18n/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2517,6 +2517,7 @@
"ok": "确定",
"okay": "了解",
"onboardingContinue": "继续",
"onboardingContinueAnonymous": "以匿名身份继续",
"onboardingCreateAccount": "创建账号",
"onboardingLogIn": "登录",
"onboardingRealmsDesc": "探索按兴趣组织的各类社群。从同好小组到创意团体,找到属于你的那群人。",
Expand Down
1 change: 1 addition & 0 deletions assets/i18n/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -2412,6 +2412,7 @@
"ok": "確定",
"okay": "瞭解",
"onboardingContinue": "繼續",
"onboardingContinueAnonymous": "以匿名身分繼續",
"onboardingCreateAccount": "建立帳號",
"onboardingLogIn": "登入",
"onboardingRealmsDesc": "探索按興趣組織的各類社群。從同好小組到創意團體,找到屬於你的那群人。",
Expand Down
45 changes: 34 additions & 11 deletions lib/chat/widgets/chat_list_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1289,12 +1289,14 @@ class _ChatListAppBar extends HookConsumerWidget {
final List<SnChatGroup> chatGroups;
final Future<void> Function() onChatGroupsChanged;
final String? accountId;
final Color foreground;

const _ChatListAppBar({
required this.tabController,
required this.chatGroups,
required this.onChatGroupsChanged,
required this.accountId,
required this.foreground,
});

@override
Expand All @@ -1314,6 +1316,7 @@ class _ChatListAppBar extends HookConsumerWidget {
Widget buildInviteButton() {
return IconButton(
tooltip: 'Chat Invites',
color: foreground,
onPressed: openInvites,
icon: Badge(
label: Text(
Expand Down Expand Up @@ -1354,6 +1357,7 @@ class _ChatListAppBar extends HookConsumerWidget {
Symbols.inbox,
fill: tabController.index == 0 ? 1 : 0,
),
color: foreground,
onPressed: () => tabController.animateTo(0),
tooltip: 'chatTabAll'.tr(),
),
Expand All @@ -1362,6 +1366,7 @@ class _ChatListAppBar extends HookConsumerWidget {
Symbols.person,
fill: tabController.index == 1 ? 1 : 0,
),
color: foreground,
onPressed: () => tabController.animateTo(1),
tooltip: 'chatTabDirect'.tr(),
),
Expand All @@ -1370,6 +1375,7 @@ class _ChatListAppBar extends HookConsumerWidget {
Symbols.group,
fill: tabController.index == 2 ? 1 : 0,
),
color: foreground,
onPressed: () => tabController.animateTo(2),
tooltip: 'chatTabGroup'.tr(),
),
Expand All @@ -1387,13 +1393,11 @@ class _ChatListAppBar extends HookConsumerWidget {
size: 24,
speed: 7,
fontSize: 12,
color: Theme.of(
context,
).colorScheme.onSurfaceVariant.withOpacity(0.65),
color: foreground.withOpacity(0.65),
),
),
),
const _MarkAllReadButton(),
_MarkAllReadButton(color: foreground),
buildInviteButton(),
],
),
Expand All @@ -1403,7 +1407,9 @@ class _ChatListAppBar extends HookConsumerWidget {
}

class _MarkAllReadButton extends ConsumerWidget {
const _MarkAllReadButton();
final Color? color;

const _MarkAllReadButton({this.color});

@override
Widget build(BuildContext context, WidgetRef ref) {
Expand All @@ -1415,17 +1421,14 @@ class _MarkAllReadButton extends ConsumerWidget {
}

return IconButton(
color: color,
icon: readSyncState.isLoading
? SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
child: CircularProgressIndicator(strokeWidth: 2, color: color),
)
: Icon(
Symbols.done_all,
),
: Icon(Symbols.done_all),
tooltip: 'Mark all as read',
onPressed: readSyncState.isLoading
? null
Expand Down Expand Up @@ -2125,6 +2128,20 @@ class ChatListWidget extends HookConsumerWidget {
);
}

final colorScheme = Theme.of(context).colorScheme;
final appBarTransparent = ref.watch(
appSettingsProvider.select((s) => s.appBarTransparent),
);
// With the transparent app bar setting off the header is a solid primary
// band, matching the explore page; with it on it defers to the theme's
// transparent treatment. The foreground has to be threaded into every
// child because `flexibleSpace` is not covered by the AppBar's own
// foreground `IconTheme`.
final appBarForeground = appBarTransparent
? (Theme.of(context).appBarTheme.foregroundColor ??
colorScheme.onSurface)
: colorScheme.onPrimary;

return AppScaffold(
extendBody: false,
floatingActionButton: const ChatFabWidget().padding(
Expand All @@ -2133,13 +2150,19 @@ class ChatListWidget extends HookConsumerWidget {
appBar: AppBar(
leading: null,
automaticallyImplyLeading: false,
// Null keeps the theme background (transparent when the setting is on).
backgroundColor: appBarTransparent ? null : colorScheme.primary,
foregroundColor: appBarForeground,
surfaceTintColor: Colors.transparent,
scrolledUnderElevation: 0,
flexibleSpace: Stack(
children: [
_ChatListAppBar(
tabController: tabController,
chatGroups: chatGroups,
onChatGroupsChanged: refreshChatGroups,
accountId: accountId,
foreground: appBarForeground,
),
],
),
Expand Down
60 changes: 47 additions & 13 deletions lib/misc/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ class SettingsScreen extends HookConsumerWidget {
!kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux);
final isIos = !kIsWeb && Platform.isIOS;
final isWide = isWideScreen(context);
// Shared tone for the whole top area (app bar + category tab strip) so the
// gray tab strip doesn't sit under a lighter/white app bar.
final topBarColor = Theme.of(
context,
).colorScheme.surfaceContainerHighest.withOpacity(0.55);
final pools = ref.watch(poolsProvider);
final user = ref.watch(userInfoProvider);
final docBasepath = useState<String?>(null);
Expand Down Expand Up @@ -2400,15 +2405,18 @@ class SettingsScreen extends HookConsumerWidget {
}

// Narrow layout with category tabs
final colorScheme = Theme.of(context).colorScheme;
final selectedIndex = visibleCategories.indexOf(selectedCategory);
// Key only on the set of visible categories, not on the current selection.
// Tapping a tab changes `selectedCategory`, so including it here used to
// recreate the DefaultTabController on every tap, resetting its animation
// to the end value and making the tab indicator jump instead of slide.
final tabBarKey = ValueKey(
'${selectedCategory.title}:${visibleCategories.map((category) => category.title).join('|')}',
visibleCategories.map((category) => category.title).join('|'),
);
return Column(
children: [
Material(
color: colorScheme.surfaceContainerHighest.withOpacity(0.55),
color: topBarColor,
child: DefaultTabController(
key: tabBarKey,
length: visibleCategories.length,
Expand All @@ -2429,16 +2437,28 @@ class SettingsScreen extends HookConsumerWidget {
),
),
Expanded(
child: selectedCategory.wideContent != null
? selectedCategory.wideContent!(context)
: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 24),
child: _SettingsSection(
title: selectedCategory.title,
localizedTitleKey: selectedCategory.localizedTitleKey,
children: selectedCategory.children,
),
),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
switchInCurve: Curves.easeOut,
switchOutCurve: Curves.easeIn,
layoutBuilder: (currentChild, previousChildren) => Stack(
fit: StackFit.expand,
children: [...previousChildren, ?currentChild],
),
child: KeyedSubtree(
key: ValueKey(selectedCategory.title),
child: selectedCategory.wideContent != null
? selectedCategory.wideContent!(context)
: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 24),
child: _SettingsSection(
title: selectedCategory.title,
localizedTitleKey: selectedCategory.localizedTitleKey,
children: selectedCategory.children,
),
),
),
),
),
],
);
Expand All @@ -2451,6 +2471,16 @@ class SettingsScreen extends HookConsumerWidget {
controller: searchController,
focusNode: searchFocusNode,
constraints: const BoxConstraints(maxWidth: 420, minHeight: 36),
// Flat, shadowless search field so it blends into the app bar instead
// of floating above it with the default M3 elevation (6dp + shadow).
elevation: const WidgetStatePropertyAll(0),
shadowColor: const WidgetStatePropertyAll(Colors.transparent),
surfaceTintColor: const WidgetStatePropertyAll(Colors.transparent),
// One tone deeper than the surrounding top bar so the field still
// reads clearly against the unified gray background.
backgroundColor: WidgetStatePropertyAll(
Theme.of(context).colorScheme.surfaceContainerHighest,
),
hintText: 'searchSettings'.tr(),
hintStyle: WidgetStatePropertyAll(
TextStyle(
Expand Down Expand Up @@ -2486,6 +2516,10 @@ class SettingsScreen extends HookConsumerWidget {
),
leading: const AutoLeadingButton(),
elevation: 0,
// Match the category tab strip so the entire top reads as one surface.
backgroundColor: topBarColor,
surfaceTintColor: Colors.transparent,
scrolledUnderElevation: 0,
),
body: LayoutBuilder(
builder: (context, constraints) {
Expand Down
13 changes: 11 additions & 2 deletions lib/posts/widgets/compose/post_shared.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2074,6 +2074,15 @@ class PostBody extends ConsumerWidget {
fontSize:
Theme.of(context).textTheme.bodyMedium!.fontSize! * (textScale ?? 1),
);
// The attachment carousel is a `CarouselView`, whose padding is applied to
// every item — so passing the body gutter verbatim also made it the gap
// between two images (an 8px gutter became a 16px gap). Halve it for the
// horizontal carousel so images sit 8px apart while the edge still roughly
// matches the body text; the column layout keeps the full gutter because
// its spacing comes from the column itself.
final containedAttachmentInset = isInteractive
? renderingPadding.horizontal / 2
: renderingPadding.horizontal;

if (item.debugRank != null && kDebugMode) {
metadataChildren.add(
Expand Down Expand Up @@ -2398,9 +2407,9 @@ class PostBody extends ConsumerWidget {
isColumn: !isInteractive,
isFullBleed: !useContainedAttachments,
padding: EdgeInsets.fromLTRB(
useContainedAttachments ? renderingPadding.horizontal : 0,
useContainedAttachments ? containedAttachmentInset : 0,
4,
useContainedAttachments ? renderingPadding.horizontal : 0,
useContainedAttachments ? containedAttachmentInset : 0,
4,
),
borderRadius: useContainedAttachments ? 12 : 8,
Expand Down
Loading