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

fix(feed): post-login appearance

+36 -54
+1 -18
lib/src/features/feed/ui/widgets/images/image_carousel.dart
··· 25 25 late List<Widget> _cachedPages; 26 26 int currentIndex = 0; 27 27 bool _imagesPreloaded = false; 28 - // Track which images have already been revealed to prevent animation restart 29 - final Set<int> _revealedImages = {}; 30 28 31 29 @override 32 30 void initState() { ··· 103 101 return child; 104 102 } 105 103 if (frame != null) { 106 - // Check if this image has already been revealed to prevent 107 - // animation restart on subsequent frameBuilder calls 108 - if (_revealedImages.contains(index)) { 109 - return child; 110 - } 111 - // Mark as revealed before animating 112 - _revealedImages.add(index); 113 - // Use TweenAnimationBuilder for smooth fade-in on first render 114 - return TweenAnimationBuilder<double>( 115 - tween: Tween(begin: 0, end: 1), 116 - duration: const Duration(milliseconds: 300), 117 - curve: Curves.easeIn, 118 - builder: (context, opacity, _) { 119 - return Opacity(opacity: opacity, child: child); 120 - }, 121 - ); 104 + return child; 122 105 } 123 106 return const SizedBox.shrink(); 124 107 },
+11 -29
lib/src/features/feed/ui/widgets/videos/video_player.dart
··· 46 46 late AnimationController _bounceController; 47 47 late Animation<double> _bounceAnimation; 48 48 49 - // For fade-in animation 50 - late AnimationController _fadeController; 51 - late Animation<double> _fadeAnimation; 52 - 53 49 int? _lastNavigationIndex; 54 50 int? _lastFeedIndex; 55 51 bool? _lastFeedSettingsVisible; ··· 72 68 ).animate( 73 69 CurvedAnimation(parent: _bounceController, curve: Curves.elasticOut), 74 70 ); 75 - _fadeController = AnimationController( 76 - duration: const Duration(milliseconds: 400), 77 - vsync: this, 78 - ); 79 - _fadeAnimation = CurvedAnimation( 80 - parent: _fadeController, 81 - curve: Curves.easeIn, 82 - ); 83 71 initVideoPlayer(); 84 72 GetIt.I<LogService>() 85 73 .getLogger('PostVideoPlayer') ··· 98 86 @override 99 87 void dispose() { 100 88 _bounceController.dispose(); 101 - _fadeController.dispose(); 102 89 videoController?.dispose(); 103 90 super.dispose(); 104 91 } ··· 158 145 setState(() { 159 146 videoController = videoControllerTemp; 160 147 }); 161 - // Start fade-in animation 162 - _fadeController.forward(); 163 148 } catch (e) { 164 149 if (!mounted) return; 165 150 } ··· 325 310 alignment: Alignment.center, 326 311 children: [ 327 312 Positioned.fill( 328 - child: FadeTransition( 329 - opacity: _fadeAnimation, 330 - child: 331 - videoSize != null && videoSize.width > 0 && videoSize.height > 0 332 - ? FittedBox( 333 - fit: fitMode, 334 - child: SizedBox( 335 - width: videoSize.width, 336 - height: videoSize.height, 337 - child: BetterPlayer(controller: videoController!), 338 - ), 339 - ) 340 - : BetterPlayer(controller: videoController!), 341 - ), 313 + child: 314 + videoSize != null && videoSize.width > 0 && videoSize.height > 0 315 + ? FittedBox( 316 + fit: fitMode, 317 + child: SizedBox( 318 + width: videoSize.width, 319 + height: videoSize.height, 320 + child: BetterPlayer(controller: videoController!), 321 + ), 322 + ) 323 + : BetterPlayer(controller: videoController!), 342 324 ), 343 325 Positioned.fill( 344 326 child: GestureDetector(
+19 -6
lib/src/features/settings/providers/settings_provider.dart
··· 86 86 87 87 @override 88 88 SettingsState build() { 89 - // Watch the preferences provider - when it updates, we'll rebuild 90 - ref.watch(userPreferencesProvider); 89 + // Note: We intentionally don't watch userPreferencesProvider here. 90 + // Watching it causes rebuilds that can race with loadSettings() and 91 + // reset the state. Instead, we explicitly call syncPreferencesFromServer() 92 + // when we need to refresh preferences. 91 93 92 94 // Preserve state across rebuilds to prevent feeds tabs from disappearing 93 95 listenSelf((previous, next) { 94 96 _preservedState = next; 95 97 }); 96 98 97 - // If we've already loaded settings once, preserve the state instead of 98 - // resetting to default. This prevents the UI from flickering when 99 - // userPreferencesProvider triggers a rebuild. 99 + // If we've already loaded settings once, preserve the state 100 100 if (_hasLoadedSettings && _preservedState != null) { 101 101 return _preservedState!; 102 102 } ··· 136 136 // Wait for auth to be initialized before trying to load settings 137 137 final authRepository = sprkRepository.authRepository; 138 138 await authRepository.initializationComplete; 139 + 140 + // Don't load settings if not authenticated - wait for login 141 + if (!authRepository.isAuthenticated) { 142 + return; 143 + } 139 144 140 145 // Get preferences from the provider (waits for it to load if needed) 141 146 final preferences = await _getPreferences(); ··· 291 296 /// - Manually from the settings UI if user wants to refresh preferences 292 297 Future<void> syncPreferencesFromServer() async { 293 298 try { 294 - // Reset load state to force a fresh load from server 299 + // Reset all load state to force a fresh load from server 300 + // Reset flags to handle race conditions (e.g., login while loading) 295 301 _hasLoadedSettings = false; 302 + _isLoadingSettings = false; 303 + _defaultLabelerEnsured = false; 304 + // Refresh preferences from server - use Future to avoid modifying 305 + // provider during widget build phase 306 + await Future(() async { 307 + await ref.read(userPreferencesProvider.notifier).refresh(); 308 + }); 296 309 await loadSettings(); 297 310 logger.d('Preferences synced successfully'); 298 311 } catch (e) {
+5 -1
lib/src/sprk_app.dart
··· 26 26 void initState() { 27 27 super.initState(); 28 28 ref.read(themeProvider.notifier).initialize(); 29 - _initializeApp(); 29 + // Defer initialization to after the widget tree is built 30 + // to avoid modifying providers during build 31 + WidgetsBinding.instance.addPostFrameCallback((_) { 32 + _initializeApp(); 33 + }); 30 34 } 31 35 32 36 Future<void> _initializeApp() async {