[READ ONLY MIRROR] Open Source TikTok alternative built on AT Protocol github.com/sprksocial/client
flutter atproto video dart
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: dm ui pass

+205 -329
-151
lib/src/core/design_system/components/molecules/glass_input.dart
··· 1 - import 'dart:ui'; 2 - 3 - import 'package:flutter/material.dart'; 4 - import 'package:spark/src/core/design_system/components/atoms/icons.dart'; 5 - import 'package:spark/src/core/design_system/tokens/typography.dart'; 6 - 7 - class GlassInput extends StatelessWidget { 8 - final TextEditingController? controller; 9 - final String hintText; 10 - final List<Widget>? leadingWidgets; 11 - final List<Widget>? actionWidgets; 12 - final VoidCallback? onSendMessage; 13 - final double borderRadius; 14 - 15 - const GlassInput._({ 16 - required this.controller, 17 - required this.hintText, 18 - required this.leadingWidgets, 19 - required this.actionWidgets, 20 - required this.onSendMessage, 21 - required this.borderRadius, 22 - super.key, 23 - }); 24 - 25 - const GlassInput.comment({ 26 - Key? key, 27 - TextEditingController? controller, 28 - String hintText = '', 29 - List<Widget>? leadingWidgets, 30 - List<Widget>? actionWidgets, 31 - }) : this._( 32 - key: key, 33 - controller: controller, 34 - hintText: hintText, 35 - leadingWidgets: leadingWidgets, 36 - actionWidgets: actionWidgets, 37 - borderRadius: 50, 38 - onSendMessage: null, 39 - ); 40 - 41 - const GlassInput.chat({ 42 - Key? key, 43 - TextEditingController? controller, 44 - String hintText = '', 45 - List<Widget>? leadingWidgets, 46 - VoidCallback? onSendMessage, 47 - }) : this._( 48 - key: key, 49 - controller: controller, 50 - hintText: hintText, 51 - leadingWidgets: leadingWidgets, 52 - onSendMessage: onSendMessage, 53 - borderRadius: 25, 54 - actionWidgets: null, 55 - ); 56 - 57 - const GlassInput.search({ 58 - Key? key, 59 - TextEditingController? controller, 60 - String hintText = '', 61 - List<Widget>? leadingWidgets, 62 - List<Widget>? actionWidgets, 63 - }) : this._( 64 - key: key, 65 - controller: controller, 66 - hintText: hintText, 67 - leadingWidgets: leadingWidgets, 68 - actionWidgets: actionWidgets, 69 - borderRadius: 15, 70 - onSendMessage: null, 71 - ); 72 - 73 - @override 74 - Widget build(BuildContext context) { 75 - final isDark = Theme.of(context).brightness == Brightness.dark; 76 - return ClipRRect( 77 - borderRadius: BorderRadius.circular(borderRadius), 78 - child: BackdropFilter( 79 - filter: ImageFilter.blur(sigmaX: 25, sigmaY: 25), 80 - child: Container( 81 - height: 38, 82 - decoration: BoxDecoration( 83 - color: isDark 84 - ? Colors.white.withAlpha(13) 85 - : Colors.black.withAlpha(13), 86 - borderRadius: BorderRadius.circular(borderRadius), 87 - border: Border.all( 88 - color: isDark 89 - ? Colors.white.withAlpha(37) 90 - : Colors.black.withAlpha(37), 91 - ), 92 - ), 93 - child: Padding( 94 - padding: const EdgeInsets.symmetric(horizontal: 12), 95 - child: Row( 96 - children: [ 97 - if (leadingWidgets != null) ...leadingWidgets!, 98 - 99 - if (leadingWidgets != null && leadingWidgets!.isNotEmpty) 100 - const SizedBox(width: 8), 101 - 102 - Expanded( 103 - child: TextField( 104 - controller: controller, 105 - style: AppTypography.textExtraSmallThin, 106 - decoration: InputDecoration( 107 - hintText: hintText, 108 - hintStyle: AppTypography.textExtraSmallThin, 109 - border: InputBorder.none, 110 - focusedBorder: InputBorder.none, 111 - focusColor: Colors.transparent, 112 - fillColor: Colors.transparent, 113 - hoverColor: Colors.transparent, 114 - isDense: true, 115 - contentPadding: const EdgeInsets.symmetric( 116 - horizontal: 4, 117 - vertical: 4, 118 - ), 119 - ), 120 - ), 121 - ), 122 - 123 - if (actionWidgets != null && actionWidgets!.isNotEmpty) 124 - const SizedBox(width: 8), 125 - 126 - if (actionWidgets != null) ...actionWidgets!, 127 - 128 - if (onSendMessage != null) ...[ 129 - const SizedBox(width: 6), 130 - IconButton( 131 - visualDensity: VisualDensity.compact, 132 - padding: EdgeInsets.zero, 133 - constraints: const BoxConstraints( 134 - minWidth: 32, 135 - minHeight: 32, 136 - ), 137 - onPressed: onSendMessage, 138 - icon: AppIcons.send( 139 - size: 18, 140 - color: isDark ? Colors.white : Colors.black, 141 - ), 142 - ), 143 - ], 144 - ], 145 - ), 146 - ), 147 - ), 148 - ), 149 - ); 150 - } 151 - }
+104
lib/src/core/design_system/components/molecules/input_field.dart
··· 1 + import 'package:flutter/material.dart'; 2 + import 'package:spark/src/core/design_system/components/atoms/icons.dart'; 3 + 4 + class InputField extends StatelessWidget { 5 + final TextEditingController? controller; 6 + final String hintText; 7 + final List<Widget>? leadingWidgets; 8 + final List<Widget>? actionWidgets; 9 + final VoidCallback? onSendMessage; 10 + 11 + const InputField._({ 12 + required this.controller, 13 + required this.hintText, 14 + required this.leadingWidgets, 15 + required this.actionWidgets, 16 + required this.onSendMessage, 17 + super.key, 18 + }); 19 + 20 + const InputField.comment({ 21 + Key? key, 22 + TextEditingController? controller, 23 + String hintText = '', 24 + List<Widget>? leadingWidgets, 25 + List<Widget>? actionWidgets, 26 + }) : this._( 27 + key: key, 28 + controller: controller, 29 + hintText: hintText, 30 + leadingWidgets: leadingWidgets, 31 + actionWidgets: actionWidgets, 32 + onSendMessage: null, 33 + ); 34 + 35 + const InputField.chat({ 36 + Key? key, 37 + TextEditingController? controller, 38 + String hintText = '', 39 + List<Widget>? leadingWidgets, 40 + VoidCallback? onSendMessage, 41 + }) : this._( 42 + key: key, 43 + controller: controller, 44 + hintText: hintText, 45 + leadingWidgets: leadingWidgets, 46 + onSendMessage: onSendMessage, 47 + actionWidgets: null, 48 + ); 49 + 50 + const InputField.search({ 51 + Key? key, 52 + TextEditingController? controller, 53 + String hintText = '', 54 + List<Widget>? leadingWidgets, 55 + List<Widget>? actionWidgets, 56 + }) : this._( 57 + key: key, 58 + controller: controller, 59 + hintText: hintText, 60 + leadingWidgets: leadingWidgets, 61 + actionWidgets: actionWidgets, 62 + onSendMessage: null, 63 + ); 64 + 65 + @override 66 + Widget build(BuildContext context) { 67 + final theme = Theme.of(context); 68 + 69 + Widget? leading; 70 + if (leadingWidgets != null && leadingWidgets!.isNotEmpty) { 71 + leading = leadingWidgets!.length == 1 72 + ? leadingWidgets!.first 73 + : Row(mainAxisSize: MainAxisSize.min, children: leadingWidgets!); 74 + } 75 + 76 + final trailingWidgets = <Widget>[ 77 + if (actionWidgets != null) ...actionWidgets!, 78 + if (onSendMessage != null) 79 + IconButton( 80 + visualDensity: VisualDensity.compact, 81 + padding: EdgeInsets.zero, 82 + constraints: const BoxConstraints(minWidth: 32, minHeight: 32), 83 + onPressed: onSendMessage, 84 + icon: AppIcons.send(size: 18, color: theme.colorScheme.onSurface), 85 + ), 86 + ]; 87 + 88 + Widget? trailing; 89 + if (trailingWidgets.isNotEmpty) { 90 + trailing = trailingWidgets.length == 1 91 + ? trailingWidgets.first 92 + : Row(mainAxisSize: MainAxisSize.min, children: trailingWidgets); 93 + } 94 + 95 + return TextField( 96 + controller: controller, 97 + decoration: InputDecoration( 98 + hintText: hintText, 99 + prefixIcon: leading, 100 + suffixIcon: trailing, 101 + ), 102 + ); 103 + } 104 + }
+12 -68
lib/src/core/design_system/templates/chat_list_page_template.dart
··· 1 1 import 'package:flutter/material.dart'; 2 2 import 'package:spark/src/core/design_system/components/atoms/icons.dart'; 3 - import 'package:spark/src/core/design_system/components/atoms/tab_item.dart'; 4 - import 'package:spark/src/core/design_system/components/molecules/app_tab_bar.dart'; 5 3 import 'package:spark/src/core/design_system/components/molecules/glass_avatar.dart'; 6 4 import 'package:spark/src/core/design_system/tokens/typography.dart'; 7 5 ··· 29 27 const ChatListPageTemplate({ 30 28 required this.items, 31 29 required this.onItemTap, 32 - required this.selectedTabIndex, 33 - required this.onTabChanged, 34 30 super.key, 35 31 this.title = 'Chat', 36 32 this.onAddTap, 37 33 this.onSearchTap, 38 - this.activityWidget, 39 34 this.onRefresh, 40 35 }); 41 36 42 37 final String title; 43 38 final List<ChatListItemData> items; 44 39 final void Function(int index) onItemTap; 45 - final int selectedTabIndex; 46 - final void Function(int index) onTabChanged; 47 40 final VoidCallback? onAddTap; 48 41 final VoidCallback? onSearchTap; 49 - final Widget? activityWidget; 50 42 final Future<void> Function()? onRefresh; 51 43 52 44 @override ··· 72 64 ), 73 65 body: Column( 74 66 children: [ 75 - _Tabs(selectedIndex: selectedTabIndex, onChanged: onTabChanged), 76 67 Expanded( 77 - child: selectedTabIndex == 0 78 - ? RefreshIndicator( 79 - onRefresh: onRefresh ?? () async {}, 80 - child: ListView.separated( 81 - padding: EdgeInsets.zero, 82 - itemCount: items.length, 83 - separatorBuilder: (_, _) => const SizedBox.shrink(), 84 - itemBuilder: (context, index) => _ChatTile( 85 - data: items[index], 86 - onTap: () => onItemTap(index), 87 - ), 88 - ), 89 - ) 90 - : (activityWidget ?? const SizedBox.shrink()), 68 + child: RefreshIndicator( 69 + onRefresh: onRefresh ?? () async {}, 70 + child: ListView.separated( 71 + padding: EdgeInsets.zero, 72 + itemCount: items.length, 73 + separatorBuilder: (_, _) => const SizedBox.shrink(), 74 + itemBuilder: (context, index) => _ChatTile( 75 + data: items[index], 76 + onTap: () => onItemTap(index), 77 + ), 78 + ), 79 + ), 91 80 ), 92 81 ], 93 82 ), 94 - ); 95 - } 96 - } 97 - 98 - class _Tabs extends StatelessWidget { 99 - const _Tabs({required this.selectedIndex, required this.onChanged}); 100 - final int selectedIndex; 101 - final void Function(int) onChanged; 102 - 103 - @override 104 - Widget build(BuildContext context) { 105 - final theme = Theme.of(context); 106 - final inactive = theme.colorScheme.onSurface.withAlpha(179); 107 - 108 - return AppTabBar( 109 - tabs: [ 110 - AppTabItem( 111 - activeChild: const Text( 112 - 'Messages', 113 - style: AppTypography.textMediumBold, 114 - ), 115 - inactiveChild: Text( 116 - 'Messages', 117 - style: AppTypography.textMediumBold.copyWith(color: inactive), 118 - ), 119 - isSelected: selectedIndex == 0, 120 - onTap: () => onChanged(0), 121 - indicatorColor: theme.colorScheme.onSurface, 122 - ), 123 - // AppTabItem( 124 - // activeChild: Text( 125 - // 'Activity', 126 - // style: AppTypography.textMediumBold.copyWith( 127 - // color: theme.colorScheme.onSurface, 128 - // ), 129 - // ), 130 - // inactiveChild: Text( 131 - // 'Activity', 132 - // style: AppTypography.textMediumBold.copyWith(color: inactive), 133 - // ), 134 - // isSelected: selectedIndex == 1, 135 - // onTap: () => onChanged(1), 136 - // indicatorColor: theme.colorScheme.onSurface, 137 - // ), 138 - ], 139 83 ); 140 84 } 141 85 }
+2 -2
lib/src/core/design_system/templates/chat_thread_page_template.dart
··· 1 1 import 'package:flutter/material.dart'; 2 2 import 'package:spark/src/core/design_system/components/atoms/buttons/app_leading_button.dart'; 3 - import 'package:spark/src/core/design_system/components/molecules/glass_input.dart'; 3 + import 'package:spark/src/core/design_system/components/molecules/input_field.dart'; 4 4 import 'package:spark/src/core/design_system/components/molecules/profile_avatar.dart'; 5 5 import 'package:spark/src/core/design_system/tokens/typography.dart'; 6 6 ··· 75 75 top: false, 76 76 child: Padding( 77 77 padding: const EdgeInsets.fromLTRB(12, 8, 12, 12), 78 - child: GlassInput.chat( 78 + child: InputField.chat( 79 79 controller: textController, 80 80 hintText: 'Message...', 81 81 onSendMessage: onSend,
+2 -2
lib/src/core/design_system/templates/image_review_page_template.dart
··· 4 4 import 'package:spark/src/core/design_system/components/atoms/buttons/app_leading_button.dart'; 5 5 import 'package:spark/src/core/design_system/components/atoms/buttons/long_button.dart'; 6 6 import 'package:spark/src/core/design_system/components/atoms/icons.dart'; 7 - import 'package:spark/src/core/design_system/components/molecules/glass_input.dart'; 7 + import 'package:spark/src/core/design_system/components/molecules/input_field.dart'; 8 8 import 'package:spark/src/core/design_system/tokens/colors.dart'; 9 9 import 'package:spark/src/core/design_system/tokens/shapes.dart'; 10 10 import 'package:spark/src/core/design_system/tokens/typography.dart'; ··· 355 355 return Column( 356 356 crossAxisAlignment: CrossAxisAlignment.start, 357 357 children: [ 358 - GlassInput.search( 358 + InputField.search( 359 359 controller: controller, 360 360 hintText: 'Add a description... (optional)', 361 361 ),
+2 -2
lib/src/core/design_system/templates/video_review_page_template.dart
··· 1 1 import 'package:flutter/material.dart'; 2 2 import 'package:spark/src/core/design_system/components/atoms/buttons/app_leading_button.dart'; 3 3 import 'package:spark/src/core/design_system/components/atoms/buttons/long_button.dart'; 4 - import 'package:spark/src/core/design_system/components/molecules/glass_input.dart'; 4 + import 'package:spark/src/core/design_system/components/molecules/input_field.dart'; 5 5 import 'package:spark/src/core/design_system/tokens/colors.dart'; 6 6 import 'package:spark/src/core/design_system/tokens/shapes.dart'; 7 7 import 'package:spark/src/core/design_system/tokens/typography.dart'; ··· 206 206 return Column( 207 207 crossAxisAlignment: CrossAxisAlignment.start, 208 208 children: [ 209 - GlassInput.search( 209 + InputField.search( 210 210 controller: controller, 211 211 hintText: 'Add a description... (optional)', 212 212 ),
-43
lib/src/features/messages/ui/pages/messages_page.dart
··· 17 17 } 18 18 19 19 class _MessagesPageState extends ConsumerState<MessagesPage> { 20 - int _selectedTabIndex = 0; 21 - 22 20 @override 23 21 Widget build(BuildContext context) { 24 22 final logger = GetIt.instance<LogService>().getLogger('MessagesPage'); ··· 53 51 54 52 return ChatListPageTemplate( 55 53 items: items, 56 - selectedTabIndex: _selectedTabIndex, 57 - onTabChanged: (i) => setState(() => _selectedTabIndex = i), 58 54 onItemTap: (index) async { 59 55 final profile = data.conversations[index].$1; 60 56 final convo = data.conversations[index].$2; ··· 71 67 onAddTap: () => context.router.push(const NewChatSearchRoute()), 72 68 onSearchTap: () {}, 73 69 onRefresh: refreshAndInvalidate, 74 - activityWidget: const ActivitiesTab(), 75 70 ); 76 71 }, 77 72 loading: () { ··· 121 116 } 122 117 } 123 118 } 124 - 125 - class ActivitiesTab extends StatelessWidget { 126 - const ActivitiesTab({super.key}); 127 - 128 - @override 129 - Widget build(BuildContext context) { 130 - // TODO: Implement activities functionality when ActivityList is available 131 - return Center( 132 - child: Column( 133 - mainAxisAlignment: MainAxisAlignment.center, 134 - children: [ 135 - Icon( 136 - FluentIcons.star_24_regular, 137 - size: 64, 138 - color: Theme.of(context).colorScheme.onSurface.withAlpha(128), 139 - ), 140 - const SizedBox(height: 16), 141 - Text( 142 - 'Activities', 143 - style: TextStyle( 144 - fontSize: 18, 145 - color: Theme.of(context).colorScheme.onSurface.withAlpha(128), 146 - fontWeight: FontWeight.w500, 147 - ), 148 - ), 149 - const SizedBox(height: 8), 150 - Text( 151 - 'Activity features coming soon', 152 - style: TextStyle( 153 - fontSize: 14, 154 - color: Theme.of(context).colorScheme.onSurface.withAlpha(128), 155 - ), 156 - ), 157 - ], 158 - ), 159 - ); 160 - } 161 - }
+31 -33
lib/src/features/messages/ui/pages/new_chat_search_page.dart
··· 3 3 import 'package:flutter/material.dart'; 4 4 import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 5 import 'package:get_it/get_it.dart'; 6 + import 'package:spark/src/core/design_system/components/atoms/buttons/app_leading_button.dart'; 6 7 import 'package:spark/src/core/design_system/components/molecules/profile_card.dart'; 7 8 import 'package:spark/src/core/network/atproto/data/models/actor_models.dart'; 8 9 import 'package:spark/src/core/network/messages/data/repository/messages_repository.dart'; ··· 56 57 children: [ 57 58 Padding( 58 59 padding: const EdgeInsets.all(16), 59 - child: TextField( 60 - controller: _searchController, 61 - decoration: InputDecoration( 62 - hintText: 'Search users', 63 - prefixIcon: Icon( 64 - FluentIcons.search_24_regular, 65 - color: theme.textTheme.bodyMedium?.color, 60 + child: Row( 61 + children: [ 62 + const AppLeadingButton(tooltip: 'Back'), 63 + const SizedBox(width: 8), 64 + Expanded( 65 + child: TextField( 66 + controller: _searchController, 67 + decoration: InputDecoration( 68 + hintText: 'Search users', 69 + prefixIcon: const Icon( 70 + FluentIcons.search_24_regular, 71 + ), 72 + suffixIcon: _searchController.text.isNotEmpty 73 + ? IconButton( 74 + iconSize: 20, 75 + splashRadius: 20, 76 + onPressed: () { 77 + _searchController.clear(); 78 + ref 79 + .read(searchProvider.notifier) 80 + .updateQuery(''); 81 + }, 82 + icon: const Icon( 83 + FluentIcons.dismiss_24_regular, 84 + ), 85 + ) 86 + : null, 87 + ), 88 + ), 66 89 ), 67 - filled: true, 68 - suffixIcon: _searchController.text.isNotEmpty 69 - ? IconButton( 70 - iconSize: 20, 71 - splashRadius: 20, 72 - onPressed: () { 73 - _searchController.clear(); 74 - ref.read(searchProvider.notifier).updateQuery(''); 75 - }, 76 - icon: const Icon(FluentIcons.dismiss_24_regular), 77 - ) 78 - : null, 79 - fillColor: colorScheme.surfaceContainerLow.withAlpha(50), 80 - enabledBorder: OutlineInputBorder( 81 - borderRadius: BorderRadius.circular(8), 82 - borderSide: BorderSide(color: colorScheme.outline), 83 - ), 84 - border: OutlineInputBorder( 85 - borderRadius: BorderRadius.circular(8), 86 - borderSide: BorderSide(color: colorScheme.outline), 87 - ), 88 - contentPadding: const EdgeInsets.symmetric( 89 - horizontal: 16, 90 - vertical: 12, 91 - ), 92 - ), 90 + ], 93 91 ), 94 92 ), 95 93 // ==== Stories or Search Results ====
+28 -19
lib/src/features/messages/ui/widgets/message_bubble.dart
··· 64 64 ] else if (!isCurrentUser) ...[ 65 65 const SizedBox(width: 40), 66 66 ], 67 - Flexible( 68 - child: Container( 69 - padding: hasEmbeds 70 - ? const EdgeInsets.symmetric(horizontal: 2, vertical: 2) 71 - : const EdgeInsets.symmetric(horizontal: 16, vertical: 10), 72 - decoration: BoxDecoration( 73 - color: isCurrentUser 74 - ? AppColors.primary 75 - : isDarkMode 76 - ? Colors.grey.shade800 77 - : Colors.grey.shade200, 78 - borderRadius: BorderRadius.circular(20), 79 - ), 67 + if (!hasText && hasEmbeds) 68 + Flexible( 80 69 child: Column( 81 70 crossAxisAlignment: CrossAxisAlignment.start, 82 71 mainAxisSize: MainAxisSize.min, 83 - children: [ 84 - if (hasEmbeds) ...embeds!, 85 - if (hasEmbeds && hasText) const SizedBox(height: 2), 86 - if (hasText) Text(cleanedMessage), 87 - ], 72 + children: embeds!, 73 + ), 74 + ) 75 + else 76 + Flexible( 77 + child: Container( 78 + padding: hasEmbeds 79 + ? const EdgeInsets.symmetric(horizontal: 2, vertical: 2) 80 + : const EdgeInsets.symmetric(horizontal: 16, vertical: 10), 81 + decoration: BoxDecoration( 82 + color: isCurrentUser 83 + ? AppColors.primary 84 + : isDarkMode 85 + ? Colors.grey.shade800 86 + : Colors.grey.shade200, 87 + borderRadius: BorderRadius.circular(20), 88 + ), 89 + child: Column( 90 + crossAxisAlignment: CrossAxisAlignment.start, 91 + mainAxisSize: MainAxisSize.min, 92 + children: [ 93 + if (hasEmbeds) ...embeds!, 94 + if (hasEmbeds && hasText) const SizedBox(height: 2), 95 + if (hasText) Text(cleanedMessage), 96 + ], 97 + ), 88 98 ), 89 99 ), 90 - ), 91 100 ], 92 101 ), 93 102 );
+22 -7
lib/src/features/messages/ui/widgets/messages_list.dart
··· 240 240 reverse: true, 241 241 itemCount: messages.length, 242 242 itemBuilder: (context, index) { 243 - final message = messages[messages.length - 1 - index]; 243 + final messageIndex = messages.length - 1 - index; 244 + final message = messages[messageIndex]; 244 245 final isCurrentUser = 245 246 currentUserDid != null && message.sender.did == currentUserDid; 246 - final hasPreviousMessage = index < messages.length - 1; 247 + final hasNewerMessage = messageIndex + 1 < messages.length; 247 248 final showAvatar = 248 249 !isCurrentUser && 249 - (index == 0 || 250 - (hasPreviousMessage && 251 - messages[messages.length - 1 - index - 1].sender.did != 252 - message.sender.did)); 250 + (!hasNewerMessage || 251 + messages[messageIndex + 1].sender.did != message.sender.did); 253 252 254 253 return Column( 255 254 children: [ ··· 637 636 if (snapshot.connectionState == ConnectionState.waiting) { 638 637 return _embedSkeleton(context); 639 638 } 639 + if (snapshot.hasError) { 640 + return _embedUnavailableIndicator(context); 641 + } 640 642 final post = snapshot.data; 641 - if (post == null) return const SizedBox.shrink(); 643 + if (post == null) return _embedUnavailableIndicator(context); 642 644 643 645 final (thumbUrl, isVideo) = _deriveThumb(post); 644 646 ··· 710 712 color: theme.colorScheme.surfaceContainerHighest, 711 713 borderRadius: BorderRadius.circular(18), 712 714 ), 715 + ), 716 + ), 717 + ); 718 + } 719 + 720 + Widget _embedUnavailableIndicator(BuildContext context) { 721 + final theme = Theme.of(context); 722 + return Padding( 723 + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4), 724 + child: Text( 725 + 'Post unavailable', 726 + style: theme.textTheme.bodySmall?.copyWith( 727 + color: theme.colorScheme.onSurface.withAlpha(150), 713 728 ), 714 729 ), 715 730 );
+2 -2
lib/src/features/search/ui/pages/search_page.dart
··· 2 2 import 'package:fluentui_system_icons/fluentui_system_icons.dart'; 3 3 import 'package:flutter/material.dart'; 4 4 import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 - import 'package:spark/src/core/design_system/components/molecules/glass_input.dart'; 5 + import 'package:spark/src/core/design_system/components/molecules/input_field.dart'; 6 6 import 'package:spark/src/core/design_system/templates/explore_page_template.dart'; 7 7 import 'package:spark/src/features/search/providers/post_search_provider.dart'; 8 8 import 'package:spark/src/features/search/providers/search_provider.dart'; ··· 52 52 return DefaultTabController( 53 53 length: 2, 54 54 child: ExplorePageTemplate( 55 - searchWidget: GlassInput.search( 55 + searchWidget: InputField.search( 56 56 controller: _searchController, 57 57 hintText: 'Search users, posts...', 58 58 leadingWidgets: const [