[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.

remove weird stories logic

+16 -87
+1 -1
lib/src/core/design_system/components/molecules/story_circle.dart
··· 184 184 decoration: BoxDecoration( 185 185 shape: BoxShape.circle, 186 186 gradient: AppGradients.accent, 187 - border: Border.all(width: 2), 187 + border: Border.all(width: 2, color: Theme.of(context).colorScheme.surface), 188 188 ), 189 189 child: AppIcons.add(size: 16, color: Colors.white), 190 190 ),
+15 -86
lib/src/features/stories/ui/widgets/stories_list.dart
··· 1 1 import 'package:auto_route/auto_route.dart'; 2 2 import 'package:flutter/material.dart'; 3 3 import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 - import 'package:sparksocial/src/core/design_system/components/atoms/icons.dart'; 5 4 import 'package:sparksocial/src/core/design_system/components/molecules/create_media_sheet.dart'; 6 5 import 'package:sparksocial/src/core/design_system/components/molecules/story_circle.dart'; 7 - import 'package:sparksocial/src/core/design_system/tokens/gradients.dart'; 8 6 import 'package:sparksocial/src/core/media/create_media_actions.dart'; 9 - import 'package:sparksocial/src/core/network/atproto/data/models/models.dart'; 10 7 import 'package:sparksocial/src/core/routing/app_router.dart'; 11 8 import 'package:sparksocial/src/features/auth/providers/auth_providers.dart'; 12 9 import 'package:sparksocial/src/features/profile/providers/profile_provider.dart'; ··· 65 62 data: (data) { 66 63 final session = ref.read(sessionProvider); 67 64 final currentUserDid = session?.did; 68 - 69 - // Find if current user has stories in the list 70 - ProfileViewBasic? currentUserAuthor; 71 - final authorsList = <MapEntry<ProfileViewBasic, List<StoryView>>>[]; 72 - 73 - for (final entry in data.storiesByAuthor.entries) { 74 - if (entry.key.did == currentUserDid) { 75 - currentUserAuthor = entry.key; 76 - } else { 77 - authorsList.add(entry); 78 - } 79 - } 80 - 81 - final userHasStories = currentUserAuthor != null && data.storiesByAuthor[currentUserAuthor]!.isNotEmpty; 82 - 83 - // Calculate item count: +1 for "Your story" (merged create + story), + authorsList.length for other authors 84 - final itemCount = 1 + authorsList.length; 65 + final authorsList = data.storiesByAuthor.entries.toList(); 85 66 86 67 return ListView.builder( 87 68 scrollDirection: Axis.horizontal, 88 69 padding: const EdgeInsets.symmetric(horizontal: 16), 89 - itemCount: itemCount, 70 + itemCount: authorsList.length + 1, 90 71 itemBuilder: (context, index) { 72 + // First item is always the create button 91 73 if (index == 0) { 92 - // "Your story" - show story circle with plus button overlay if has stories, or just create button if no stories 93 74 final userAvatarUrl = ref 94 75 .read(profileNotifierProvider(did: currentUserDid!)) 95 76 .when( ··· 98 79 loading: () => '', 99 80 ); 100 81 101 - if (userHasStories) { 102 - // User has stories - show story circle with plus button overlay 103 - return GestureDetector( 104 - onTap: () { 105 - context.router.push( 106 - AllStoriesRoute( 107 - storiesByAuthor: data.storiesByAuthor, 108 - // User is first in the combined list 109 - ), 110 - ); 111 - }, 112 - onLongPress: () => _showCreateMenu(context), 113 - child: Padding( 114 - padding: const EdgeInsets.only(right: 12), 115 - child: Stack( 116 - clipBehavior: Clip.none, 117 - children: [ 118 - StoryCircle.story( 119 - userName: 'Your story', 120 - imageUrl: userAvatarUrl, 121 - ), 122 - // Plus button overlay positioned at bottom right of the image circle 123 - // StoryCircle is 102px tall, image circle is 74px, so bottom: 28 positions it at bottom of image 124 - Positioned( 125 - right: 4, 126 - bottom: 28, // 102 (total height) - 74 (image size) = 28 127 - child: GestureDetector( 128 - onTap: () => _showCreateMenu(context), 129 - behavior: HitTestBehavior.opaque, 130 - child: Container( 131 - width: 22, 132 - height: 22, 133 - decoration: BoxDecoration( 134 - shape: BoxShape.circle, 135 - gradient: AppGradients.accent, 136 - border: Border.all(), 137 - ), 138 - child: AppIcons.add(size: 16, color: Colors.white), 139 - ), 140 - ), 141 - ), 142 - ], 143 - ), 82 + return GestureDetector( 83 + onTap: () => _showCreateMenu(context), 84 + child: Padding( 85 + padding: const EdgeInsets.only(right: 12), 86 + child: StoryCircle.create( 87 + userName: 'Create', 88 + imageUrl: userAvatarUrl, 144 89 ), 145 - ); 146 - } else { 147 - // User has no stories - show create button 148 - return GestureDetector( 149 - onTap: () => _showCreateMenu(context), 150 - child: Padding( 151 - padding: const EdgeInsets.only(right: 12), 152 - child: StoryCircle.create( 153 - userName: 'Your story', 154 - imageUrl: userAvatarUrl, 155 - ), 156 - ), 157 - ); 158 - } 90 + ), 91 + ); 159 92 } 160 93 161 - // Other authors' stories 162 - final realIndex = index - 1; 163 - final authorEntry = authorsList[realIndex]; 94 + // All other items are author stories 95 + final authorEntry = authorsList[index - 1]; 164 96 final author = authorEntry.key; 165 - 166 - // Adjust initialAuthorIndex to account for current user being first 167 - final initialAuthorIndex = currentUserAuthor != null ? realIndex + 1 : realIndex; 168 97 169 98 return GestureDetector( 170 99 onTap: () { 171 100 context.router.push( 172 101 AllStoriesRoute( 173 102 storiesByAuthor: data.storiesByAuthor, 174 - initialAuthorIndex: initialAuthorIndex, 103 + initialAuthorIndex: index - 1, 175 104 ), 176 105 ); 177 106 },