diff --git a/distribution/store-assets/README.md b/distribution/store-assets/README.md
index 5e561f3..554d517 100644
--- a/distribution/store-assets/README.md
+++ b/distribution/store-assets/README.md
@@ -34,8 +34,18 @@ Schibsted Grotesk / Instrument Sans), flat shapes, alternating light and dark.
| 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 |
+| App Store iPhone 6.1" / 6.3" screenshots | `ios/iphone-6.3in/` | 1206 × 2622 |
+| App Store iPhone Duo (foldable), portrait | `ios/iphone-fold-portrait/` | 2007 × 2853 |
+| App Store iPhone Duo (foldable), landscape | `ios/iphone-fold-landscape/` | 2853 × 2007 |
+| App Store header | `ios/header/` | 5244 × 2950, 3840 × 1646 |
+| App Store search results | `ios/search-results/` | 5244 × 2950, 3840 × 2560, 1920 × 1280 |
| iOS icon reference | `ios/icon-1024.png` | 1024 × 1024 |
+The iPad 13" slot (2064 × 2752 and 2752 × 2064) is covered by `ios/ipad/` and
+`ios/ipad-landscape/`. The header and search-results banners are one brand
+design (name, tagline, iPad and iPhone) rendered at each size. App previews
+(video) are not produced here.
+
Upload in numeric order. The App Store uses the icon embedded in the uploaded
build; `ios/icon-1024.png` is only a reference copy. Screenshots, the feature
graphic and the iOS icon are opaque RGB PNGs; the Play icon is 32-bit RGBA.
diff --git a/distribution/store-assets/index.html b/distribution/store-assets/index.html
index a8c914d..9d1bcb9 100644
--- a/distribution/store-assets/index.html
+++ b/distribution/store-assets/index.html
@@ -1 +1 @@
-
Noo store assetsNoo / 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
+Noo store assetsNoo / 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
ios/iphone-6.3in/01-accounts.png · 1206 × 2622
ios/iphone-6.3in/02-locks.png · 1206 × 2622
ios/iphone-6.3in/03-sync.png · 1206 × 2622
ios/iphone-6.3in/04-sharing.png · 1206 × 2622
ios/iphone-6.3in/05-external.png · 1206 × 2622
ios/iphone-fold-portrait/01-accounts.png · 2007 × 2853
ios/iphone-fold-portrait/02-locks.png · 2007 × 2853
ios/iphone-fold-portrait/03-sync.png · 2007 × 2853
ios/iphone-fold-portrait/04-sharing.png · 2007 × 2853
ios/iphone-fold-portrait/05-external.png · 2007 × 2853
ios/iphone-fold-landscape/01-accounts.png · 2853 × 2007
ios/iphone-fold-landscape/02-locks.png · 2853 × 2007
ios/iphone-fold-landscape/03-sync.png · 2853 × 2007
ios/iphone-fold-landscape/04-sharing.png · 2853 × 2007
ios/iphone-fold-landscape/05-external.png · 2853 × 2007
ios/header/header-5244x2950.png · 5244 × 2950
ios/header/header-3840x1646.png · 3840 × 1646
ios/search-results/search-5244x2950.png · 5244 × 2950
ios/search-results/search-3840x2560.png · 3840 × 2560
ios/search-results/search-1920x1280.png · 1920 × 1280
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/header/header-3840x1646.png b/distribution/store-assets/ios/header/header-3840x1646.png
new file mode 100644
index 0000000..4ace069
Binary files /dev/null and b/distribution/store-assets/ios/header/header-3840x1646.png differ
diff --git a/distribution/store-assets/ios/header/header-5244x2950.png b/distribution/store-assets/ios/header/header-5244x2950.png
new file mode 100644
index 0000000..d595b3b
Binary files /dev/null and b/distribution/store-assets/ios/header/header-5244x2950.png differ
diff --git a/distribution/store-assets/ios/iphone-6.3in/01-accounts.png b/distribution/store-assets/ios/iphone-6.3in/01-accounts.png
new file mode 100644
index 0000000..8018630
Binary files /dev/null and b/distribution/store-assets/ios/iphone-6.3in/01-accounts.png differ
diff --git a/distribution/store-assets/ios/iphone-6.3in/02-locks.png b/distribution/store-assets/ios/iphone-6.3in/02-locks.png
new file mode 100644
index 0000000..c659c7e
Binary files /dev/null and b/distribution/store-assets/ios/iphone-6.3in/02-locks.png differ
diff --git a/distribution/store-assets/ios/iphone-6.3in/03-sync.png b/distribution/store-assets/ios/iphone-6.3in/03-sync.png
new file mode 100644
index 0000000..9f163db
Binary files /dev/null and b/distribution/store-assets/ios/iphone-6.3in/03-sync.png differ
diff --git a/distribution/store-assets/ios/iphone-6.3in/04-sharing.png b/distribution/store-assets/ios/iphone-6.3in/04-sharing.png
new file mode 100644
index 0000000..bed7071
Binary files /dev/null and b/distribution/store-assets/ios/iphone-6.3in/04-sharing.png differ
diff --git a/distribution/store-assets/ios/iphone-6.3in/05-external.png b/distribution/store-assets/ios/iphone-6.3in/05-external.png
new file mode 100644
index 0000000..390c8e9
Binary files /dev/null and b/distribution/store-assets/ios/iphone-6.3in/05-external.png differ
diff --git a/distribution/store-assets/ios/iphone-fold-landscape/01-accounts.png b/distribution/store-assets/ios/iphone-fold-landscape/01-accounts.png
new file mode 100644
index 0000000..5c20ce4
Binary files /dev/null and b/distribution/store-assets/ios/iphone-fold-landscape/01-accounts.png differ
diff --git a/distribution/store-assets/ios/iphone-fold-landscape/02-locks.png b/distribution/store-assets/ios/iphone-fold-landscape/02-locks.png
new file mode 100644
index 0000000..1700e10
Binary files /dev/null and b/distribution/store-assets/ios/iphone-fold-landscape/02-locks.png differ
diff --git a/distribution/store-assets/ios/iphone-fold-landscape/03-sync.png b/distribution/store-assets/ios/iphone-fold-landscape/03-sync.png
new file mode 100644
index 0000000..5d75ae0
Binary files /dev/null and b/distribution/store-assets/ios/iphone-fold-landscape/03-sync.png differ
diff --git a/distribution/store-assets/ios/iphone-fold-landscape/04-sharing.png b/distribution/store-assets/ios/iphone-fold-landscape/04-sharing.png
new file mode 100644
index 0000000..32afd10
Binary files /dev/null and b/distribution/store-assets/ios/iphone-fold-landscape/04-sharing.png differ
diff --git a/distribution/store-assets/ios/iphone-fold-landscape/05-external.png b/distribution/store-assets/ios/iphone-fold-landscape/05-external.png
new file mode 100644
index 0000000..3c420ec
Binary files /dev/null and b/distribution/store-assets/ios/iphone-fold-landscape/05-external.png differ
diff --git a/distribution/store-assets/ios/iphone-fold-portrait/01-accounts.png b/distribution/store-assets/ios/iphone-fold-portrait/01-accounts.png
new file mode 100644
index 0000000..55fb324
Binary files /dev/null and b/distribution/store-assets/ios/iphone-fold-portrait/01-accounts.png differ
diff --git a/distribution/store-assets/ios/iphone-fold-portrait/02-locks.png b/distribution/store-assets/ios/iphone-fold-portrait/02-locks.png
new file mode 100644
index 0000000..8460835
Binary files /dev/null and b/distribution/store-assets/ios/iphone-fold-portrait/02-locks.png differ
diff --git a/distribution/store-assets/ios/iphone-fold-portrait/03-sync.png b/distribution/store-assets/ios/iphone-fold-portrait/03-sync.png
new file mode 100644
index 0000000..7bb3f90
Binary files /dev/null and b/distribution/store-assets/ios/iphone-fold-portrait/03-sync.png differ
diff --git a/distribution/store-assets/ios/iphone-fold-portrait/04-sharing.png b/distribution/store-assets/ios/iphone-fold-portrait/04-sharing.png
new file mode 100644
index 0000000..5276dcf
Binary files /dev/null and b/distribution/store-assets/ios/iphone-fold-portrait/04-sharing.png differ
diff --git a/distribution/store-assets/ios/iphone-fold-portrait/05-external.png b/distribution/store-assets/ios/iphone-fold-portrait/05-external.png
new file mode 100644
index 0000000..0818ba1
Binary files /dev/null and b/distribution/store-assets/ios/iphone-fold-portrait/05-external.png differ
diff --git a/distribution/store-assets/ios/search-results/search-1920x1280.png b/distribution/store-assets/ios/search-results/search-1920x1280.png
new file mode 100644
index 0000000..afecbb7
Binary files /dev/null and b/distribution/store-assets/ios/search-results/search-1920x1280.png differ
diff --git a/distribution/store-assets/ios/search-results/search-3840x2560.png b/distribution/store-assets/ios/search-results/search-3840x2560.png
new file mode 100644
index 0000000..5969022
Binary files /dev/null and b/distribution/store-assets/ios/search-results/search-3840x2560.png differ
diff --git a/distribution/store-assets/ios/search-results/search-5244x2950.png b/distribution/store-assets/ios/search-results/search-5244x2950.png
new file mode 100644
index 0000000..d595b3b
Binary files /dev/null and b/distribution/store-assets/ios/search-results/search-5244x2950.png differ
diff --git a/distribution/store-assets/manifest.json b/distribution/store-assets/manifest.json
index fc0386d..3f8120e 100644
--- a/distribution/store-assets/manifest.json
+++ b/distribution/store-assets/manifest.json
@@ -359,6 +359,186 @@
"mode": "RGB",
"story": "external"
},
+ {
+ "file": "ios/iphone-6.3in/01-accounts.png",
+ "size": [
+ 1206,
+ 2622
+ ],
+ "mode": "RGB",
+ "story": "accounts"
+ },
+ {
+ "file": "ios/iphone-6.3in/02-locks.png",
+ "size": [
+ 1206,
+ 2622
+ ],
+ "mode": "RGB",
+ "story": "locks"
+ },
+ {
+ "file": "ios/iphone-6.3in/03-sync.png",
+ "size": [
+ 1206,
+ 2622
+ ],
+ "mode": "RGB",
+ "story": "sync"
+ },
+ {
+ "file": "ios/iphone-6.3in/04-sharing.png",
+ "size": [
+ 1206,
+ 2622
+ ],
+ "mode": "RGB",
+ "story": "sharing"
+ },
+ {
+ "file": "ios/iphone-6.3in/05-external.png",
+ "size": [
+ 1206,
+ 2622
+ ],
+ "mode": "RGB",
+ "story": "external"
+ },
+ {
+ "file": "ios/iphone-fold-portrait/01-accounts.png",
+ "size": [
+ 2007,
+ 2853
+ ],
+ "mode": "RGB",
+ "story": "accounts"
+ },
+ {
+ "file": "ios/iphone-fold-portrait/02-locks.png",
+ "size": [
+ 2007,
+ 2853
+ ],
+ "mode": "RGB",
+ "story": "locks"
+ },
+ {
+ "file": "ios/iphone-fold-portrait/03-sync.png",
+ "size": [
+ 2007,
+ 2853
+ ],
+ "mode": "RGB",
+ "story": "sync"
+ },
+ {
+ "file": "ios/iphone-fold-portrait/04-sharing.png",
+ "size": [
+ 2007,
+ 2853
+ ],
+ "mode": "RGB",
+ "story": "sharing"
+ },
+ {
+ "file": "ios/iphone-fold-portrait/05-external.png",
+ "size": [
+ 2007,
+ 2853
+ ],
+ "mode": "RGB",
+ "story": "external"
+ },
+ {
+ "file": "ios/iphone-fold-landscape/01-accounts.png",
+ "size": [
+ 2853,
+ 2007
+ ],
+ "mode": "RGB",
+ "story": "accounts"
+ },
+ {
+ "file": "ios/iphone-fold-landscape/02-locks.png",
+ "size": [
+ 2853,
+ 2007
+ ],
+ "mode": "RGB",
+ "story": "locks"
+ },
+ {
+ "file": "ios/iphone-fold-landscape/03-sync.png",
+ "size": [
+ 2853,
+ 2007
+ ],
+ "mode": "RGB",
+ "story": "sync"
+ },
+ {
+ "file": "ios/iphone-fold-landscape/04-sharing.png",
+ "size": [
+ 2853,
+ 2007
+ ],
+ "mode": "RGB",
+ "story": "sharing"
+ },
+ {
+ "file": "ios/iphone-fold-landscape/05-external.png",
+ "size": [
+ 2853,
+ 2007
+ ],
+ "mode": "RGB",
+ "story": "external"
+ },
+ {
+ "file": "ios/header/header-5244x2950.png",
+ "size": [
+ 5244,
+ 2950
+ ],
+ "mode": "RGB",
+ "story": "banner"
+ },
+ {
+ "file": "ios/header/header-3840x1646.png",
+ "size": [
+ 3840,
+ 1646
+ ],
+ "mode": "RGB",
+ "story": "banner"
+ },
+ {
+ "file": "ios/search-results/search-5244x2950.png",
+ "size": [
+ 5244,
+ 2950
+ ],
+ "mode": "RGB",
+ "story": "banner"
+ },
+ {
+ "file": "ios/search-results/search-3840x2560.png",
+ "size": [
+ 3840,
+ 2560
+ ],
+ "mode": "RGB",
+ "story": "banner"
+ },
+ {
+ "file": "ios/search-results/search-1920x1280.png",
+ "size": [
+ 1920,
+ 1280
+ ],
+ "mode": "RGB",
+ "story": "banner"
+ },
{
"file": "android/icon-512.png",
"size": [
diff --git a/distribution/store-assets/store-listing-assets.zip b/distribution/store-assets/store-listing-assets.zip
index ec8aaa7..90e849d 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/compose.py b/distribution/store-assets/tools/compose.py
index 2aa2323..8312804 100644
--- a/distribution/store-assets/tools/compose.py
+++ b/distribution/store-assets/tools/compose.py
@@ -60,6 +60,19 @@ TARGETS = [
('android/tablet-7in-landscape', 'atabletl', (1920, 1200), 'landscape'),
('android/tablet-10in-landscape', 'atabletl', (2560, 1600), 'landscape'),
('ios/ipad-landscape', 'ipadl', (2752, 2064), 'landscape'),
+ # Newer App Store slots. iPad 13" (2064x2752, 2752x2064) is the two above.
+ ('ios/iphone-6.3in', 'iphone', (1206, 2622), 'phone'),
+ ('ios/iphone-fold-portrait', 'ipad', (2007, 2853), 'tablet'),
+ ('ios/iphone-fold-landscape', 'ipadl', (2853, 2007), 'landscape'),
+]
+
+# App Store product-page banners: (folder, file name, size).
+HEROES = [
+ ('ios/header', 'header-5244x2950.png', (5244, 2950)),
+ ('ios/header', 'header-3840x1646.png', (3840, 1646)),
+ ('ios/search-results', 'search-5244x2950.png', (5244, 2950)),
+ ('ios/search-results', 'search-3840x2560.png', (3840, 2560)),
+ ('ios/search-results', 'search-1920x1280.png', (1920, 1280)),
]
@@ -215,6 +228,56 @@ def story_canvas(story, size, kind, device):
return im
+def hero_canvas(size):
+ """Brand banner: name and tagline left, iPad (landscape) and iPhone right."""
+ t = THEMES['light']
+ w, h = size
+ im = background(size, t)
+ d = ImageDraw.Draw(im)
+ margin = round(min(w * .06, h * .13))
+ colw = round(w * (.30 if w / h > 2 else .34))
+ # Text column, vertically centered as a block.
+ icon_px = round(h * .105)
+ head = round(h * .092)
+ sub_size = round(h * .034)
+ block = icon_px + round(h * .05) + round(head * 2.35) + round(sub_size * 4.4)
+ y = (h - block) // 2
+ icon = Image.open(ROOT / 'assets/icon/app_icon.png').convert('RGBA').resize((icon_px, icon_px), Image.Resampling.LANCZOS)
+ im.paste(icon, (margin, y), rounded_mask((icon_px, icon_px), round(icon_px * .24)))
+ spaced(d, (margin + icon_px + round(h * .025), y + icon_px // 2 - round(h * .02)), 'NOOCLOUD',
+ font(round(h * .034), 'Bold', 'InstrumentSans'), t['accent_text'], h * .006)
+ y += icon_px + round(h * .05)
+ for index, line in enumerate(('The Nextcloud app', 'that just works.')):
+ 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)
+ fnt = body_font(sub_size, 'Regular')
+ chars = max(16, int(colw / (sub_size * .52)))
+ for line in textwrap.wrap('Multiple accounts, locks, offline sync, sharing and external storage.', chars):
+ d.text((margin, y), line, font=fnt, fill=t['fg2'])
+ y += round(sub_size * 1.4)
+ # Devices: iPad landscape with the iPhone overlapping its bottom-right corner.
+ x0 = margin + colw + round(w * .03)
+ region_w = w - x0 - margin
+ ipad_h = round(h * .72)
+ ipad_w = round(ipad_h * 4 / 3)
+ phone_h = round(ipad_h * 1.02)
+ phone_w = round(phone_h * 0.4614)
+ total = ipad_w + round(phone_w * .7)
+ if total > region_w:
+ k = region_w / total
+ ipad_h, ipad_w, phone_h, phone_w = (round(v * k) for v in (ipad_h, ipad_w, phone_h, phone_w))
+ total = ipad_w + round(phone_w * .7)
+ x = x0 + (region_w - total) // 2
+ top = (h - ipad_h) // 2 - round(h * .03)
+ paste_panel(im, OUT / 'source/ipadl/external.png', (x, top, ipad_w, ipad_h), round(h * .028), t)
+ paste_panel(im, OUT / 'source/iphone/offline.png',
+ (x + ipad_w - round(phone_w * .3), top + ipad_h - phone_h + round(h * .07), phone_w, phone_h),
+ round(h * .035), t)
+ return im
+
+
def check(path, size, mode):
image = Image.open(path)
assert image.size == tuple(size) and image.mode == mode, path
@@ -234,6 +297,13 @@ for folder, device, size, kind in TARGETS:
manifest.append({'file': str(path.relative_to(OUT)), 'size': list(size), 'mode': 'RGB',
'story': story['key']})
+for folder, name, size in HEROES:
+ dest = OUT / folder
+ dest.mkdir(parents=True, exist_ok=True)
+ path = dest / name
+ hero_canvas(size).save(path, optimize=True)
+ manifest.append({'file': str(path.relative_to(OUT)), 'size': list(size), 'mode': 'RGB', 'story': 'banner'})
+
# Store icons: Play wants a 512 px PNG, App Store Connect takes the icon from
# the uploaded build (this 1024 px copy is only a reference).
for platform, px, source in [