diff --git a/distribution/store-assets/README.md b/distribution/store-assets/README.md index 5c0f5e9..5e561f3 100644 --- a/distribution/store-assets/README.md +++ b/distribution/store-assets/README.md @@ -12,6 +12,11 @@ involved. The five screenshots follow the Features section of the website 4. Sharing: the Share sheet (people, groups, public link) 5. External storage: Files with the mounted-storage section +The landscape tablet sets show the app's real tablet layout (sidebar and +toolbar), captured from the actual shell widget. Portrait and landscape tablet +screenshots go in the same store slot; upload whichever orientation you want +to show, or both. + Look: the app's own design tokens (warm neutrals, one violet accent, Schibsted Grotesk / Instrument Sans), flat shapes, alternating light and dark. @@ -26,6 +31,9 @@ Schibsted Grotesk / Instrument Sans), flat shapes, alternating light and dark. | Google Play 10-inch tablet screenshots | `android/tablet-10in/` | 1600 × 2560 | | App Store iPhone screenshots (6.9" / 6.7" slot) | `ios/iphone/` | 1290 × 2796 | | App Store iPad screenshots (13" slot) | `ios/ipad/` | 2064 × 2752 | +| Google Play 7-inch tablet, landscape | `android/tablet-7in-landscape/` | 1920 × 1200 | +| Google Play 10-inch tablet, landscape | `android/tablet-10in-landscape/` | 2560 × 1600 | +| App Store iPad screenshots, landscape (13" slot) | `ios/ipad-landscape/` | 2752 × 2064 | | iOS icon reference | `ios/icon-1024.png` | 1024 × 1024 | Upload in numeric order. The App Store uses the icon embedded in the uploaded diff --git a/distribution/store-assets/android/tablet-10in-landscape/01-accounts.png b/distribution/store-assets/android/tablet-10in-landscape/01-accounts.png new file mode 100644 index 0000000..66259fe Binary files /dev/null and b/distribution/store-assets/android/tablet-10in-landscape/01-accounts.png differ diff --git a/distribution/store-assets/android/tablet-10in-landscape/02-locks.png b/distribution/store-assets/android/tablet-10in-landscape/02-locks.png new file mode 100644 index 0000000..3a15b1f Binary files /dev/null and b/distribution/store-assets/android/tablet-10in-landscape/02-locks.png differ diff --git a/distribution/store-assets/android/tablet-10in-landscape/03-sync.png b/distribution/store-assets/android/tablet-10in-landscape/03-sync.png new file mode 100644 index 0000000..2165003 Binary files /dev/null and b/distribution/store-assets/android/tablet-10in-landscape/03-sync.png differ diff --git a/distribution/store-assets/android/tablet-10in-landscape/04-sharing.png b/distribution/store-assets/android/tablet-10in-landscape/04-sharing.png new file mode 100644 index 0000000..6fa0c79 Binary files /dev/null and b/distribution/store-assets/android/tablet-10in-landscape/04-sharing.png differ diff --git a/distribution/store-assets/android/tablet-10in-landscape/05-external.png b/distribution/store-assets/android/tablet-10in-landscape/05-external.png new file mode 100644 index 0000000..e213a27 Binary files /dev/null and b/distribution/store-assets/android/tablet-10in-landscape/05-external.png differ diff --git a/distribution/store-assets/android/tablet-7in-landscape/01-accounts.png b/distribution/store-assets/android/tablet-7in-landscape/01-accounts.png new file mode 100644 index 0000000..caa456d Binary files /dev/null and b/distribution/store-assets/android/tablet-7in-landscape/01-accounts.png differ diff --git a/distribution/store-assets/android/tablet-7in-landscape/02-locks.png b/distribution/store-assets/android/tablet-7in-landscape/02-locks.png new file mode 100644 index 0000000..4c6fe2d Binary files /dev/null and b/distribution/store-assets/android/tablet-7in-landscape/02-locks.png differ diff --git a/distribution/store-assets/android/tablet-7in-landscape/03-sync.png b/distribution/store-assets/android/tablet-7in-landscape/03-sync.png new file mode 100644 index 0000000..1003540 Binary files /dev/null and b/distribution/store-assets/android/tablet-7in-landscape/03-sync.png differ diff --git a/distribution/store-assets/android/tablet-7in-landscape/04-sharing.png b/distribution/store-assets/android/tablet-7in-landscape/04-sharing.png new file mode 100644 index 0000000..05bcf27 Binary files /dev/null and b/distribution/store-assets/android/tablet-7in-landscape/04-sharing.png differ diff --git a/distribution/store-assets/android/tablet-7in-landscape/05-external.png b/distribution/store-assets/android/tablet-7in-landscape/05-external.png new file mode 100644 index 0000000..3ac06fb Binary files /dev/null and b/distribution/store-assets/android/tablet-7in-landscape/05-external.png differ diff --git a/distribution/store-assets/contact-sheet.jpg b/distribution/store-assets/contact-sheet.jpg index 6ec37a8..de18163 100644 Binary files a/distribution/store-assets/contact-sheet.jpg and b/distribution/store-assets/contact-sheet.jpg differ diff --git a/distribution/store-assets/index.html b/distribution/store-assets/index.html index 75f9d4f..a8c914d 100644 --- a/distribution/store-assets/index.html +++ b/distribution/store-assets/index.html @@ -1 +1 @@ -Noo store assets

Noo / store listing assets

English · production Flutter UI · fictional offline demo data.

android/phone/01-accounts.png · 1080 × 1920
android/phone/02-locks.png · 1080 × 1920
android/phone/03-sync.png · 1080 × 1920
android/phone/04-sharing.png · 1080 × 1920
android/phone/05-external.png · 1080 × 1920
android/tablet-7in/01-accounts.png · 1200 × 1920
android/tablet-7in/02-locks.png · 1200 × 1920
android/tablet-7in/03-sync.png · 1200 × 1920
android/tablet-7in/04-sharing.png · 1200 × 1920
android/tablet-7in/05-external.png · 1200 × 1920
android/tablet-10in/01-accounts.png · 1600 × 2560
android/tablet-10in/02-locks.png · 1600 × 2560
android/tablet-10in/03-sync.png · 1600 × 2560
android/tablet-10in/04-sharing.png · 1600 × 2560
android/tablet-10in/05-external.png · 1600 × 2560
ios/iphone/01-accounts.png · 1290 × 2796
ios/iphone/02-locks.png · 1290 × 2796
ios/iphone/03-sync.png · 1290 × 2796
ios/iphone/04-sharing.png · 1290 × 2796
ios/iphone/05-external.png · 1290 × 2796
ios/ipad/01-accounts.png · 2064 × 2752
ios/ipad/02-locks.png · 2064 × 2752
ios/ipad/03-sync.png · 2064 × 2752
ios/ipad/04-sharing.png · 2064 × 2752
ios/ipad/05-external.png · 2064 × 2752
android/icon-512.png · 512 × 512
ios/icon-1024.png · 1024 × 1024
android/feature-graphic-1024x500.png · 1024 × 500
\ No newline at end of file +Noo store assets

Noo / store listing assets

English · production Flutter UI · fictional offline demo data.

android/phone/01-accounts.png · 1080 × 1920
android/phone/02-locks.png · 1080 × 1920
android/phone/03-sync.png · 1080 × 1920
android/phone/04-sharing.png · 1080 × 1920
android/phone/05-external.png · 1080 × 1920
android/tablet-7in/01-accounts.png · 1200 × 1920
android/tablet-7in/02-locks.png · 1200 × 1920
android/tablet-7in/03-sync.png · 1200 × 1920
android/tablet-7in/04-sharing.png · 1200 × 1920
android/tablet-7in/05-external.png · 1200 × 1920
android/tablet-10in/01-accounts.png · 1600 × 2560
android/tablet-10in/02-locks.png · 1600 × 2560
android/tablet-10in/03-sync.png · 1600 × 2560
android/tablet-10in/04-sharing.png · 1600 × 2560
android/tablet-10in/05-external.png · 1600 × 2560
ios/iphone/01-accounts.png · 1290 × 2796
ios/iphone/02-locks.png · 1290 × 2796
ios/iphone/03-sync.png · 1290 × 2796
ios/iphone/04-sharing.png · 1290 × 2796
ios/iphone/05-external.png · 1290 × 2796
ios/ipad/01-accounts.png · 2064 × 2752
ios/ipad/02-locks.png · 2064 × 2752
ios/ipad/03-sync.png · 2064 × 2752
ios/ipad/04-sharing.png · 2064 × 2752
ios/ipad/05-external.png · 2064 × 2752
android/tablet-7in-landscape/01-accounts.png · 1920 × 1200
android/tablet-7in-landscape/02-locks.png · 1920 × 1200
android/tablet-7in-landscape/03-sync.png · 1920 × 1200
android/tablet-7in-landscape/04-sharing.png · 1920 × 1200
android/tablet-7in-landscape/05-external.png · 1920 × 1200
android/tablet-10in-landscape/01-accounts.png · 2560 × 1600
android/tablet-10in-landscape/02-locks.png · 2560 × 1600
android/tablet-10in-landscape/03-sync.png · 2560 × 1600
android/tablet-10in-landscape/04-sharing.png · 2560 × 1600
android/tablet-10in-landscape/05-external.png · 2560 × 1600
ios/ipad-landscape/01-accounts.png · 2752 × 2064
ios/ipad-landscape/02-locks.png · 2752 × 2064
ios/ipad-landscape/03-sync.png · 2752 × 2064
ios/ipad-landscape/04-sharing.png · 2752 × 2064
ios/ipad-landscape/05-external.png · 2752 × 2064
android/icon-512.png · 512 × 512
ios/icon-1024.png · 1024 × 1024
android/feature-graphic-1024x500.png · 1024 × 500
\ No newline at end of file diff --git a/distribution/store-assets/ios/ipad-landscape/01-accounts.png b/distribution/store-assets/ios/ipad-landscape/01-accounts.png new file mode 100644 index 0000000..5bf177b Binary files /dev/null and b/distribution/store-assets/ios/ipad-landscape/01-accounts.png differ diff --git a/distribution/store-assets/ios/ipad-landscape/02-locks.png b/distribution/store-assets/ios/ipad-landscape/02-locks.png new file mode 100644 index 0000000..17d2f2e Binary files /dev/null and b/distribution/store-assets/ios/ipad-landscape/02-locks.png differ diff --git a/distribution/store-assets/ios/ipad-landscape/03-sync.png b/distribution/store-assets/ios/ipad-landscape/03-sync.png new file mode 100644 index 0000000..48a180a Binary files /dev/null and b/distribution/store-assets/ios/ipad-landscape/03-sync.png differ diff --git a/distribution/store-assets/ios/ipad-landscape/04-sharing.png b/distribution/store-assets/ios/ipad-landscape/04-sharing.png new file mode 100644 index 0000000..7fd2b70 Binary files /dev/null and b/distribution/store-assets/ios/ipad-landscape/04-sharing.png differ diff --git a/distribution/store-assets/ios/ipad-landscape/05-external.png b/distribution/store-assets/ios/ipad-landscape/05-external.png new file mode 100644 index 0000000..d830d16 Binary files /dev/null and b/distribution/store-assets/ios/ipad-landscape/05-external.png differ diff --git a/distribution/store-assets/manifest.json b/distribution/store-assets/manifest.json index 8ce3fc0..fc0386d 100644 --- a/distribution/store-assets/manifest.json +++ b/distribution/store-assets/manifest.json @@ -224,6 +224,141 @@ "mode": "RGB", "story": "external" }, + { + "file": "android/tablet-7in-landscape/01-accounts.png", + "size": [ + 1920, + 1200 + ], + "mode": "RGB", + "story": "accounts" + }, + { + "file": "android/tablet-7in-landscape/02-locks.png", + "size": [ + 1920, + 1200 + ], + "mode": "RGB", + "story": "locks" + }, + { + "file": "android/tablet-7in-landscape/03-sync.png", + "size": [ + 1920, + 1200 + ], + "mode": "RGB", + "story": "sync" + }, + { + "file": "android/tablet-7in-landscape/04-sharing.png", + "size": [ + 1920, + 1200 + ], + "mode": "RGB", + "story": "sharing" + }, + { + "file": "android/tablet-7in-landscape/05-external.png", + "size": [ + 1920, + 1200 + ], + "mode": "RGB", + "story": "external" + }, + { + "file": "android/tablet-10in-landscape/01-accounts.png", + "size": [ + 2560, + 1600 + ], + "mode": "RGB", + "story": "accounts" + }, + { + "file": "android/tablet-10in-landscape/02-locks.png", + "size": [ + 2560, + 1600 + ], + "mode": "RGB", + "story": "locks" + }, + { + "file": "android/tablet-10in-landscape/03-sync.png", + "size": [ + 2560, + 1600 + ], + "mode": "RGB", + "story": "sync" + }, + { + "file": "android/tablet-10in-landscape/04-sharing.png", + "size": [ + 2560, + 1600 + ], + "mode": "RGB", + "story": "sharing" + }, + { + "file": "android/tablet-10in-landscape/05-external.png", + "size": [ + 2560, + 1600 + ], + "mode": "RGB", + "story": "external" + }, + { + "file": "ios/ipad-landscape/01-accounts.png", + "size": [ + 2752, + 2064 + ], + "mode": "RGB", + "story": "accounts" + }, + { + "file": "ios/ipad-landscape/02-locks.png", + "size": [ + 2752, + 2064 + ], + "mode": "RGB", + "story": "locks" + }, + { + "file": "ios/ipad-landscape/03-sync.png", + "size": [ + 2752, + 2064 + ], + "mode": "RGB", + "story": "sync" + }, + { + "file": "ios/ipad-landscape/04-sharing.png", + "size": [ + 2752, + 2064 + ], + "mode": "RGB", + "story": "sharing" + }, + { + "file": "ios/ipad-landscape/05-external.png", + "size": [ + 2752, + 2064 + ], + "mode": "RGB", + "story": "external" + }, { "file": "android/icon-512.png", "size": [ diff --git a/distribution/store-assets/source/android/security.png b/distribution/store-assets/source/android/security.png index b946aa2..5dba3d1 100644 Binary files a/distribution/store-assets/source/android/security.png and b/distribution/store-assets/source/android/security.png differ diff --git a/distribution/store-assets/source/android/sync.png b/distribution/store-assets/source/android/sync.png index 203202d..58bdff6 100644 Binary files a/distribution/store-assets/source/android/sync.png and b/distribution/store-assets/source/android/sync.png differ diff --git a/distribution/store-assets/source/atablet/security.png b/distribution/store-assets/source/atablet/security.png index 4131ed9..53a3965 100644 Binary files a/distribution/store-assets/source/atablet/security.png and b/distribution/store-assets/source/atablet/security.png differ diff --git a/distribution/store-assets/source/atablet/sync.png b/distribution/store-assets/source/atablet/sync.png index f116677..a3895b9 100644 Binary files a/distribution/store-assets/source/atablet/sync.png and b/distribution/store-assets/source/atablet/sync.png differ diff --git a/distribution/store-assets/source/atabletl/accounts.png b/distribution/store-assets/source/atabletl/accounts.png new file mode 100644 index 0000000..8f5241d Binary files /dev/null and b/distribution/store-assets/source/atabletl/accounts.png differ diff --git a/distribution/store-assets/source/atabletl/external.png b/distribution/store-assets/source/atabletl/external.png new file mode 100644 index 0000000..6698f32 Binary files /dev/null and b/distribution/store-assets/source/atabletl/external.png differ diff --git a/distribution/store-assets/source/atabletl/lock.png b/distribution/store-assets/source/atabletl/lock.png new file mode 100644 index 0000000..3930f4c Binary files /dev/null and b/distribution/store-assets/source/atabletl/lock.png differ diff --git a/distribution/store-assets/source/atabletl/offline.png b/distribution/store-assets/source/atabletl/offline.png new file mode 100644 index 0000000..46f3094 Binary files /dev/null and b/distribution/store-assets/source/atabletl/offline.png differ diff --git a/distribution/store-assets/source/atabletl/security.png b/distribution/store-assets/source/atabletl/security.png new file mode 100644 index 0000000..99b3cc7 Binary files /dev/null and b/distribution/store-assets/source/atabletl/security.png differ diff --git a/distribution/store-assets/source/atabletl/sharing.png b/distribution/store-assets/source/atabletl/sharing.png new file mode 100644 index 0000000..0d0d911 Binary files /dev/null and b/distribution/store-assets/source/atabletl/sharing.png differ diff --git a/distribution/store-assets/source/atabletl/sync.png b/distribution/store-assets/source/atabletl/sync.png new file mode 100644 index 0000000..0d8d1dd Binary files /dev/null and b/distribution/store-assets/source/atabletl/sync.png differ diff --git a/distribution/store-assets/source/ipad/security.png b/distribution/store-assets/source/ipad/security.png index 4131ed9..53a3965 100644 Binary files a/distribution/store-assets/source/ipad/security.png and b/distribution/store-assets/source/ipad/security.png differ diff --git a/distribution/store-assets/source/ipad/sync.png b/distribution/store-assets/source/ipad/sync.png index f116677..a3895b9 100644 Binary files a/distribution/store-assets/source/ipad/sync.png and b/distribution/store-assets/source/ipad/sync.png differ diff --git a/distribution/store-assets/source/ipadl/accounts.png b/distribution/store-assets/source/ipadl/accounts.png new file mode 100644 index 0000000..4fe808e Binary files /dev/null and b/distribution/store-assets/source/ipadl/accounts.png differ diff --git a/distribution/store-assets/source/ipadl/external.png b/distribution/store-assets/source/ipadl/external.png new file mode 100644 index 0000000..2bb4026 Binary files /dev/null and b/distribution/store-assets/source/ipadl/external.png differ diff --git a/distribution/store-assets/source/ipadl/lock.png b/distribution/store-assets/source/ipadl/lock.png new file mode 100644 index 0000000..3930f4c Binary files /dev/null and b/distribution/store-assets/source/ipadl/lock.png differ diff --git a/distribution/store-assets/source/ipadl/offline.png b/distribution/store-assets/source/ipadl/offline.png new file mode 100644 index 0000000..46f3094 Binary files /dev/null and b/distribution/store-assets/source/ipadl/offline.png differ diff --git a/distribution/store-assets/source/ipadl/security.png b/distribution/store-assets/source/ipadl/security.png new file mode 100644 index 0000000..99b3cc7 Binary files /dev/null and b/distribution/store-assets/source/ipadl/security.png differ diff --git a/distribution/store-assets/source/ipadl/sharing.png b/distribution/store-assets/source/ipadl/sharing.png new file mode 100644 index 0000000..0184f70 Binary files /dev/null and b/distribution/store-assets/source/ipadl/sharing.png differ diff --git a/distribution/store-assets/source/ipadl/sync.png b/distribution/store-assets/source/ipadl/sync.png new file mode 100644 index 0000000..0d8d1dd Binary files /dev/null and b/distribution/store-assets/source/ipadl/sync.png differ diff --git a/distribution/store-assets/source/iphone/security.png b/distribution/store-assets/source/iphone/security.png index bea1042..5dba3d1 100644 Binary files a/distribution/store-assets/source/iphone/security.png and b/distribution/store-assets/source/iphone/security.png differ diff --git a/distribution/store-assets/source/iphone/sync.png b/distribution/store-assets/source/iphone/sync.png index 757ca6a..58bdff6 100644 Binary files a/distribution/store-assets/source/iphone/sync.png and b/distribution/store-assets/source/iphone/sync.png differ diff --git a/distribution/store-assets/store-listing-assets.zip b/distribution/store-assets/store-listing-assets.zip index 8530a63..ec8aaa7 100644 Binary files a/distribution/store-assets/store-listing-assets.zip and b/distribution/store-assets/store-listing-assets.zip differ diff --git a/distribution/store-assets/tools/capture_test.dart b/distribution/store-assets/tools/capture_test.dart index ac51c95..baa8062 100644 --- a/distribution/store-assets/tools/capture_test.dart +++ b/distribution/store-assets/tools/capture_test.dart @@ -11,6 +11,10 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:noo/main.dart' show MainShellView; +import 'package:noo/providers/recent_controller.dart'; +import 'package:noo/providers/shares_controller.dart'; +import 'package:noo/providers/trash_controller.dart'; import 'package:noo/models/app_tab.dart'; import 'package:noo/theme/design_tokens.dart'; import 'package:noo/views/lock_screen_view.dart'; @@ -169,10 +173,26 @@ class DemoOps extends ItemOperations { Future> searchSharees(String query) async => []; } +/// The shell collapses to the Offline tab alone when it thinks there is no +/// network, so the landscape (full shell) captures report an online device. +class DemoConnectivity extends ConnectivityController { + @override + bool get isOffline => false; +} + class DemoFiles extends FilesController { DemoFiles(super.session, {this.external = false}); final bool external; @override + NextcloudUserQuota? get quota => const NextcloudUserQuota( + usedBytes: 46000000000, + totalBytes: 107374182400, + usagePercentage: 0.43, + userName: 'alex', + email: 'alex@cloud.example.com', + serverVersion: '31.0.0', + ); + @override StorageScope get storageScope => external ? StorageScope.all : StorageScope.cloud; @override @@ -329,12 +349,31 @@ void main() { MockStreamHandler.inline(onListen: (arguments, events) {}), ); } + // The shell listens for share/pick intents; none ever arrive here. + for (final name in [ + 'dev.ayushya.noo/share_intent/new', + 'dev.ayushya.noo/pick_intent/new', + ]) { + messenger.setMockStreamHandler( + EventChannel(name), + MockStreamHandler.inline(onListen: (arguments, events) {}), + ); + } messenger.setMockStreamHandler( const EventChannel('dev.fluttercommunity.plus/connectivity_status'), MockStreamHandler.inline(onListen: (arguments, events) {}), ); }); - for (final device in ['android', 'atablet', 'iphone', 'ipad']) { + // `ipadl` / `atabletl` are the landscape tablet captures, which render the + // app's real shell (sidebar + toolbar) instead of the single-screen widgets. + for (final device in [ + 'android', + 'atablet', + 'atabletl', + 'iphone', + 'ipad', + 'ipadl', + ]) { for (final screen in [ 'accounts', 'lock', @@ -353,17 +392,27 @@ void main() { 'ui_lock_account_switching': true, 'ui_lock_hidden_files': true, 'ui_use_dynamic_color': false, + // Skips the shell's one-time notification-permission prompt. + 'notification_permission_asked': true, }); - final tablet = device == 'ipad' || device == 'atablet'; - final android = device == 'android' || device == 'atablet'; - final size = tablet + final landscape = device == 'ipadl' || device == 'atabletl'; + final tablet = landscape || device == 'ipad' || device == 'atablet'; + final android = + device == 'android' || + device == 'atablet' || + device == 'atabletl'; + final size = landscape + ? const Size(1024, 768) + : tablet ? const Size(768, 1024) : (android ? const Size(430, 800) : const Size(430, 932)); tester.view.devicePixelRatio = 1; tester.view.physicalSize = size; await tester.binding.setSurfaceSize(size); final key = GlobalKey(); - final connectivity = ConnectivityController(); + final connectivity = landscape + ? DemoConnectivity() + : ConnectivityController(); final session = DemoSession(connectivity); final files = DemoFiles(session, external: screen == 'external'); final settings = SettingsController(); @@ -378,6 +427,12 @@ void main() { photos: photos, favorites: favorites, ); + final trash = TrashController(session); + final shares = SharesController(session); + final recent = RecentController(session); + if (landscape && screen == 'offline') { + settings.requestTab(AppTab.offline); + } final scroll = ScrollController(); final style = android ? NooNavStyle.android : NooNavStyle.ios; final browsing = const { @@ -412,6 +467,12 @@ void main() { ChangeNotifierProvider.value(value: offline), ChangeNotifierProvider.value(value: pick), ChangeNotifierProvider.value(value: photos), + ChangeNotifierProvider.value( + value: favorites, + ), + ChangeNotifierProvider.value(value: trash), + ChangeNotifierProvider.value(value: shares), + ChangeNotifierProvider.value(value: recent), Provider.value(value: ops), ], child: MaterialApp( @@ -423,6 +484,8 @@ void main() { card ? child! : RepaintBoundary(key: key, child: child), home: screen == 'lock' ? const LockScreenView() + : landscape && browsing + ? const MainShellView() : Scaffold( body: browsing ? FilesView( @@ -438,16 +501,27 @@ void main() { ) : Align( alignment: Alignment.topCenter, - child: Builder( - builder: (context) => RepaintBoundary( - key: key, - child: ColoredBox( - color: context.nooColors.bg, - child: Padding( - padding: const EdgeInsets.all(12), - child: screen == 'security' - ? const SettingsSecuritySection() - : const SettingsFileSyncSection(), + child: ConstrainedBox( + // Landscape tablets would stretch the card + // across the whole window; keep it phone-like. + constraints: BoxConstraints( + maxWidth: landscape ? 520 : double.infinity, + ), + child: Builder( + builder: (context) => RepaintBoundary( + key: key, + child: ColoredBox( + color: context.nooColors.bg, + child: Padding( + padding: const EdgeInsets.all(12), + // The desktop-style card fills its + // height, so size it to its content. + child: IntrinsicHeight( + child: screen == 'security' + ? const SettingsSecuritySection() + : const SettingsFileSyncSection(), + ), + ), ), ), ), @@ -514,6 +588,9 @@ void main() { }); await tester.pumpWidget(const SizedBox.shrink()); scroll.dispose(); + trash.dispose(); + shares.dispose(); + recent.dispose(); pick.dispose(); offline.dispose(); sync.dispose(); diff --git a/distribution/store-assets/tools/compose.py b/distribution/store-assets/tools/compose.py index 6601cb3..2aa2323 100644 --- a/distribution/store-assets/tools/compose.py +++ b/distribution/store-assets/tools/compose.py @@ -31,7 +31,7 @@ STORIES = [ eyebrow='MULTIPLE ACCOUNTS', lines=('Every cloud,', 'one tap apart.'), sub='Personal, work and family servers together.'), - dict(key='locks', theme='dark', back='lock', front='security', card_at=.66, + dict(key='locks', theme='dark', back='lock', front='security', card_at=.66, card_at_l=.66, eyebrow='LOCKS', lines=('Locks where', 'you want them.'), sub='Protect opening Noo, switching accounts and hidden files with your device PIN or biometrics.'), @@ -56,6 +56,10 @@ TARGETS = [ ('android/tablet-10in', 'atablet', (1600, 2560), 'tablet'), ('ios/iphone', 'iphone', (1290, 2796), 'phone'), ('ios/ipad', 'ipad', (2064, 2752), 'tablet'), + # Landscape tablets show the app's real sidebar layout. + ('android/tablet-7in-landscape', 'atabletl', (1920, 1200), 'landscape'), + ('android/tablet-10in-landscape', 'atabletl', (2560, 1600), 'landscape'), + ('ios/ipad-landscape', 'ipadl', (2752, 2064), 'landscape'), ] @@ -127,7 +131,51 @@ def paste_panel(canvas, source, box, radius, t, bleed=False): return x, y, sw, sh +def landscape_canvas(story, size, device): + """Text column on the left, the real tablet UI on the right.""" + t = THEMES[story['theme']] + w, h = size + im = background(size, t) + d = ImageDraw.Draw(im) + margin = round(h * .07) + colw = round(w * .30) + y = round(h * .27) + spaced(d, (margin, y), story['eyebrow'], font(round(h * .022), 'Bold', 'InstrumentSans'), + t['accent_text'], h * .004) + y += round(h * .06) + head = round(h * .068) + for index, line in enumerate(story['lines']): + fnt, _ = fit(d, line, font, head, colw) + d.text((margin, y), line, font=fnt, fill=t['accent_text'] if index else t['fg']) + y += round(head * 1.12) + y += round(head * .2) + sub_size = round(h * .030) + fnt = body_font(sub_size, 'Regular') + for line in textwrap.wrap(story['sub'], max(16, int(colw / (sub_size * .52)))): + d.text((margin, y), line, font=fnt, fill=t['fg2']) + y += round(sub_size * 1.4) + x0 = margin + colw + round(w * .035) + src = lambda name: OUT / f'source/{device}/{name}.png' + back = Image.open(src(story['back'])) + aw, ah = w - x0 - margin, h - margin * 2 + factor = min(aw / back.width, ah / back.height) + # Centered vertically; a layered card hangs below the panel's bottom edge. + area = (x0, round((h - back.height * factor) / 2) - (round(h * .03) if story['front'] else 0), aw, ah) + radius = round(h * .03) + bx, by, bw, bh = paste_panel(im, src(story['back']), area, radius, t) + if story['front']: + card = content_crop(src(story['front'])) + scale = bw / Image.open(src(story['back'])).width + cw, ch = round(card.width * scale), round(card.height * scale) + cx = bx + round(bw * .40) + cy = by + round(bh * story.get('card_at_l', story['card_at'])) + paste_panel(im, card, (cx, cy, cw, ch), round(radius * .6), t) + return im + + def story_canvas(story, size, kind, device): + if kind == 'landscape': + return landscape_canvas(story, size, device) t = THEMES[story['theme']] w, h = size im = background(size, t) @@ -218,11 +266,12 @@ for asset in manifest: (OUT / 'manifest.json').write_text(json.dumps(manifest, indent=2) + '\n') # Review materials (not for upload): contact sheet and a gallery page. -contact = Image.new('RGB', (1920, 1500), '#1c1b18') +contact = Image.new('RGB', (1920, 2160), '#1c1b18') cd = ImageDraw.Draw(contact) cd.text((32, 20), 'Noo / store listing artwork', font=font(28), fill='#F3EFE6') rows = [('ANDROID PHONE', 'android/phone'), ('ANDROID 10" TABLET', 'android/tablet-10in'), - ('IPHONE', 'ios/iphone'), ('IPAD', 'ios/ipad')] + ('IPHONE', 'ios/iphone'), ('IPAD', 'ios/ipad'), + ('ANDROID 10" LANDSCAPE', 'android/tablet-10in-landscape'), ('IPAD LANDSCAPE', 'ios/ipad-landscape')] for row, (label, folder) in enumerate(rows): cd.text((32, 75 + row * 360), label, font=font(15, 'Bold', 'InstrumentSans'), fill='#CBA5FD') for col, path in enumerate(sorted((OUT / folder).glob('*.png'))):