From 95da5717df253018f6637ff31203b384df561158 Mon Sep 17 00:00:00 2001 From: Rajesh Malviya Date: Thu, 10 Jul 2025 01:25:17 +0530 Subject: [PATCH 1/2] store: Make GlobalStoreWidget's loading placeholder blank This removes the un-styled CircularProgressIndicator that was displayed for a brief moment, instead the user now just sees the default background color. [greg: added TODO-comments on the extra frame that seems to now be needed] --- lib/widgets/store.dart | 11 ++++++++++- test/widgets/store_test.dart | 14 ++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/widgets/store.dart b/lib/widgets/store.dart index f5fe4d3cc6..7278305b29 100644 --- a/lib/widgets/store.dart +++ b/lib/widgets/store.dart @@ -19,7 +19,7 @@ class GlobalStoreWidget extends StatefulWidget { const GlobalStoreWidget({ super.key, this.blockingFuture, - this.placeholder = const LoadingPlaceholder(), + this.placeholder = const BlankLoadingPlaceholder(), required this.child, }); @@ -341,6 +341,15 @@ class _PerAccountStoreInheritedWidget extends InheritedNotifier store != oldWidget.store; } +class BlankLoadingPlaceholder extends StatelessWidget { + const BlankLoadingPlaceholder({super.key}); + + @override + Widget build(BuildContext context) { + return const SizedBox.shrink(); + } +} + class LoadingPlaceholder extends StatelessWidget { const LoadingPlaceholder({super.key}); diff --git a/test/widgets/store_test.dart b/test/widgets/store_test.dart index 54490ede93..74b3dd68ad 100644 --- a/test/widgets/store_test.dart +++ b/test/widgets/store_test.dart @@ -70,12 +70,12 @@ void main() { return const SizedBox.shrink(); }))); // First, shows a loading page instead of child. - check(find.byType(CircularProgressIndicator)).findsOne(); + check(find.byType(BlankLoadingPlaceholder)).findsOne(); check(globalStore).isNull(); await tester.pump(); // Then after loading, mounts child instead, with provided store. - check(find.byType(CircularProgressIndicator)).findsNothing(); + check(find.byType(BlankLoadingPlaceholder)).findsNothing(); check(globalStore).identicalTo(testBinding.globalStore); await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot()); @@ -98,14 +98,15 @@ void main() { await tester.pump(); // Even after the store must have loaded, // still shows loading page while blockingFuture is pending. - check(find.byType(CircularProgressIndicator)).findsOne(); + check(find.byType(BlankLoadingPlaceholder)).findsOne(); check(find.text('done')).findsNothing(); // Once blockingFuture completes… completer.complete(); await tester.pump(); + await tester.pump(); // TODO why does GlobalStoreWidget need this extra frame? // … mounts child instead of the loading page. - check(find.byType(CircularProgressIndicator)).findsNothing(); + check(find.byType(BlankLoadingPlaceholder)).findsNothing(); check(find.text('done')).findsOne(); }); @@ -123,14 +124,15 @@ void main() { await tester.pump(); // Even after the store must have loaded, // still shows loading page while blockingFuture is pending. - check(find.byType(CircularProgressIndicator)).findsOne(); + check(find.byType(BlankLoadingPlaceholder)).findsOne(); check(find.text('done')).findsNothing(); // Once blockingFuture completes, even with an error… completer.completeError(Exception('oops')); await tester.pump(); + await tester.pump(); // TODO why does GlobalStoreWidget need this extra frame? // … mounts child instead of the loading page. - check(find.byType(CircularProgressIndicator)).findsNothing(); + check(find.byType(BlankLoadingPlaceholder)).findsNothing(); check(find.text('done')).findsOne(); }); From 59dfd0aef60f85695fbdbec17283f9a990fb41f1 Mon Sep 17 00:00:00 2001 From: Rajesh Malviya Date: Wed, 9 Jul 2025 23:40:33 +0530 Subject: [PATCH 2/2] ios: Use main background color as the splash screen Use `DesignVariables.mainBackground` as the iOS launch screen colors. Discussion: https://chat.zulip.org/#narrow/channel/530-mobile-design/topic/splash.20screen.20on.20iOS/near/2215883 Fixes: #1149 --- ios/Runner.xcodeproj/project.pbxproj | 12 ------ ios/Runner/AppDelegate.swift | 5 +++ .../LaunchBackground.colorset/Contents.json | 38 ++++++++++++++++++ .../LaunchImage.imageset/Contents.json | 23 ----------- .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 --- ios/Runner/Base.lproj/LaunchScreen.storyboard | 37 ----------------- ios/Runner/Info.plist | 7 +++- lib/widgets/theme.dart | 10 +++++ 11 files changed, 58 insertions(+), 79 deletions(-) create mode 100644 ios/Runner/Assets.xcassets/LaunchBackground.colorset/Contents.json delete mode 100644 ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 37f8231c8d..d1c3c5953d 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -12,7 +12,6 @@ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; B34E9F092D776BEB0009AED2 /* Notifications.g.swift in Sources */ = {isa = PBXBuildFile; fileRef = B34E9F082D776BEB0009AED2 /* Notifications.g.swift */; }; F311C174AF9C005CE4AADD72 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EAE3F3F518B95B7BFEB4FE7 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ @@ -47,7 +46,6 @@ 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B34E9F082D776BEB0009AED2 /* Notifications.g.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifications.g.swift; sourceTree = ""; }; B3AF53A72CA20BD10039801D /* Zulip.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Zulip.xcconfig; path = Flutter/Zulip.xcconfig; sourceTree = ""; }; @@ -112,7 +110,6 @@ 3752899A2AF472D400475D9C /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, @@ -195,7 +192,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, @@ -316,14 +312,6 @@ name = Main.storyboard; sourceTree = ""; }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index eefed07cd6..068ca5c1df 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -10,6 +10,11 @@ import Flutter didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) + + // Use `DesignVariables.mainBackground` color as the background color + // of the default UIView. + window?.backgroundColor = UIColor(named: "LaunchBackground"); + let controller = window?.rootViewController as! FlutterViewController // Retrieve the remote notification payload from launch options; diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.colorset/Contents.json b/ios/Runner/Assets.xcassets/LaunchBackground.colorset/Contents.json new file mode 100644 index 0000000000..43a02dcfa1 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF0", + "green" : "0xF0", + "red" : "0xF0" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x1D", + "green" : "0x1D", + "red" : "0x1D" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2fd4..0000000000 --- a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b70..0000000000 --- a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7c9..0000000000 --- a/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index d86c7afca7..489fb6d350 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -52,8 +52,11 @@ fetch remote-notification - UILaunchStoryboardName - LaunchScreen + UILaunchScreen + + UIColorName + LaunchBackground + UIMainStoryboardFile Main UISupportedInterfaceOrientations diff --git a/lib/widgets/theme.dart b/lib/widgets/theme.dart index ff05be7969..6039072116 100644 --- a/lib/widgets/theme.dart +++ b/lib/widgets/theme.dart @@ -174,7 +174,12 @@ class DesignVariables extends ThemeExtension { listMenuItemBg: const Color(0xffcbcdd6), listMenuItemIcon: const Color(0xff9194a3), listMenuItemText: const Color(0xff2d303c), + + // Keep the color here and the corresponding non-dark mode entry in + // ios/Runner/Assets.xcassets/LaunchBackground.colorset/Contents.json + // in sync. mainBackground: const Color(0xfff0f0f0), + neutralButtonBg: const Color(0xff8c84ae), neutralButtonLabel: const Color(0xff433d5c), radioBorder: Color(0xffbbbdc8), @@ -257,7 +262,12 @@ class DesignVariables extends ThemeExtension { listMenuItemBg: const Color(0xff2d303c), listMenuItemIcon: const Color(0xff767988), listMenuItemText: const Color(0xffcbcdd6), + + // Keep the color here and the corresponding dark mode entry in + // ios/Runner/Assets.xcassets/LaunchBackground.colorset/Contents.json + // in sync. mainBackground: const Color(0xff1d1d1d), + neutralButtonBg: const Color(0xffd4d1e0), neutralButtonLabel: const Color(0xffa9a3c2), radioBorder: Color(0xff626573),