Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions OpenDocumentReader/DocumentViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel

return

case .edit:
case .edit, .editLite:
// ready once the tools are up, which `beginEditSession` says
editDocument()

Expand Down Expand Up @@ -810,7 +810,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel
private func editSessionReady() {
isEditSessionReady = true

if ScreenshotMode.screen == .edit {
if ScreenshotMode.screen?.isEdit == true {
ScreenshotMode.markReady(view)
}
}
Expand Down
5 changes: 3 additions & 2 deletions OpenDocumentReader/Features.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ enum Features {
/// The ad banner and the consent form in front of it: Lite only.
static var withAds: Bool { LINKS_ADS }

/// Formatting, paragraph changes and pdf marks: Pro only.
static var advancedEditing: Bool { ADVANCED_EDITING }
/// Formatting, paragraph changes and pdf marks: Pro only. The Lite edit
/// screenshot turns them off, because it is taken from the Pro build.
static var advancedEditing: Bool { ADVANCED_EDITING && ScreenshotMode.screen != .editLite }
}
7 changes: 6 additions & 1 deletion OpenDocumentReader/ScreenshotMode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,17 @@ enum ScreenshotMode {
case pdf
/// a document being edited, keyboard up
case edit
/// the same edit as Lite shows it: the Pro tools dimmed, behind a badge
case editLite = "edit-lite"

/// Whether the screen is an edit, in either app.
var isEdit: Bool { self == .edit || self == .editLite }

/// The sample this screen opens, `nil` where it opens none.
var sample: String? {
switch self {
case .browser: return nil
case .text, .edit: return "text"
case .text, .edit, .editLite: return "text"
case .sheet: return "sheet"
case .office: return "word"
case .pdf: return "paper"
Expand Down
19 changes: 16 additions & 3 deletions OpenDocumentReaderUITests/ScreenshotTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ import XCTest
/// the order the store shows them in.
final class ScreenshotTests: XCTestCase {

/// Each picture's name, and the screen it is of. The number is the place
/// in the store. Lite's edit takes the place of Pro's in Lite's listing,
/// so both are `04`.
private static let pictures = [
("01-browser", "browser"),
("02-text", "text"),
("03-sheet", "sheet"),
("04-edit", "edit"),
("04-edit-lite", "edit-lite"),
("05-pdf", "pdf"),
("06-office", "office"),
]

/// Long, because it covers translating a document on a simulator that is
/// also running eleven other languages' worth of tests today.
private let readyTimeout: TimeInterval = 180
Expand Down Expand Up @@ -40,7 +53,7 @@ final class ScreenshotTests: XCTestCase {

let arguments = app.launchArguments

for (index, screen) in ["browser", "text", "sheet", "edit", "pdf", "office"].enumerated() {
for (name, screen) in Self.pictures {
app.launchArguments = arguments + ["-ODRScreenshot", screen]
app.launch()

Expand All @@ -53,11 +66,11 @@ final class ScreenshotTests: XCTestCase {
waitForTheFolderToFill(in: app)
}

if screen == "edit" {
if screen.hasPrefix("edit") {
raiseTheKeyboard(in: app)
}

Snapshots.take(String(format: "%02d-%@", index + 1, screen))
Snapshots.take(name)

// rather than leaving it running: the next launch has to go through
// didFinishLaunching again to be handed the next screen
Expand Down
9 changes: 5 additions & 4 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,10 @@ platform :ios do
)

# The Pro scheme, so no ad sdk is linked and no consent form can come up in
# front of a picture. The two apps are the same app, and what differs - the
# banner Lite carries - is not in a screenshot either way, so one set of
# pictures goes to both listings.
# front of a picture. The two apps differ only in the edit, where Lite dims
# the Pro tools: the run takes that screen a second time as Lite shows it,
# and each listing gets its own edit. The banner Lite carries is in no
# picture either way.
capture_ios_screenshots(
project: "OpenDocumentReader.xcodeproj",
scheme: "ODR Screenshots",
Expand Down Expand Up @@ -503,7 +504,7 @@ platform :ios do
# something captured has to have all of it: half a set is worse in the
# store than the set already up there.
captured = !Dir.glob(File.join(FRAMED_DIR, "*", "*.png")).empty?
sh(STORE_SCREENSHOTS, "--screenshots", FRAMED_DIR, "--stage", shots_dir) if captured
sh(STORE_SCREENSHOTS, "--screenshots", FRAMED_DIR, "--stage", shots_dir, "--app", options[:name]) if captured
UI.important("no screenshots under #{FRAMED_DIR} - writing the text only") unless captured

key_path = api_key_file
Expand Down
12 changes: 9 additions & 3 deletions fastlane/screenshots/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ The lane does these steps:

## The set

Six screens per device, in store order:
Six screens per device, in store order. The edit is taken twice:

| | |
| --- | --- |
| `01-browser` | the document browser, with one file of each format |
| `02-text` | a text document |
| `03-sheet` | a spreadsheet, with its sheet tabs |
| `04-edit` | a document in edit mode, keyboard up |
| `04-edit-lite` | the same, as Lite shows it: the Pro tools dimmed |
| `05-pdf` | a PDF, with a search under way |
| `06-office` | a Word file |

Expand All @@ -48,5 +49,10 @@ English pictures, because the app has no Hindi or Swedish UI.
## Both apps

The set is taken once, with the `ODR Screenshots` scheme. That scheme builds
the Pro target, which links no ad sdk, so no consent form can appear. Both
listings get the same pictures.
the Pro target, which links no ad sdk, so no consent form can appear.

The two apps differ only in the edit. `-ODRScreenshot edit-lite` turns the Pro
tools off in the Pro build, so Lite's edit is taken from the same build.
`scripts/store_screenshots.py --stage DIR --app lite` puts that picture in
place of `04-edit`, and each listing gets its own set. Both edits share the
headline of `04-edit` in `fastlane/frames/frames.json`.
9 changes: 7 additions & 2 deletions scripts/frame-screenshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,9 +659,14 @@ def main(argv=None):
shutil.rmtree(out, ignore_errors=True)
out.mkdir(parents=True, exist_ok=True)

# Lite's edit is framed as the screen it replaces: the same place,
# and the same headline, which is true of both apps
replaces = {lite: screen for screen, lite in store.LITE.items()}

for path in sorted(folder.glob("*.png")):
name = next((n for n in screens if path.stem.endswith(n)), None)
if name is None:
taken = next((n for n in store.CAPTURED if path.stem.endswith(n)), None)
name = replaces.get(taken, taken)
if name not in screens:
continue

with Image.open(path) as shot:
Expand Down
45 changes: 34 additions & 11 deletions scripts/store_screenshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# scripts/store_screenshots.py --languages what to capture
# scripts/store_screenshots.py check what was captured
# scripts/store_screenshots.py --stage DIR check it and stage it
# scripts/store_screenshots.py --stage DIR --app A check it and stage A's set
#
# The store has eleven locales and the app is translated into nine of them.
# The other two get the English pictures, which is what their storefront would
Expand Down Expand Up @@ -57,6 +57,18 @@
"06-office",
)

# What Lite shows in place of a screen of Pro's. The edit is the one screen
# where the two apps differ: Lite dims the Pro tools behind a badge.
LITE = {
"04-edit": "04-edit-lite",
}

APPS = ("pro", "lite")

# Every picture a run takes, longest name first, so a name that ends another
# one is never matched in its place.
CAPTURED = tuple(sorted(SCREENS + tuple(LITE.values()), key=len, reverse=True))

# What App Store Connect accepts, upright, in pixels. An app that runs on both
# has to hand in both, and the store fits every smaller iPhone and iPad from
# these two. More than one size per device because which simulator a runner has
Expand Down Expand Up @@ -125,9 +137,9 @@ def collect(directory):

pictures = {}
for path in sorted(folder.glob("*.png")):
screen = next((name for name in SCREENS if path.stem.endswith(name)), None)
screen = next((name for name in CAPTURED if path.stem.endswith(name)), None)
if screen is None:
problems.append(f"{locale}: {path.name} is not one of {', '.join(SCREENS)}")
problems.append(f"{locale}: {path.name} is not one of {', '.join(CAPTURED)}")
continue

try:
Expand All @@ -148,7 +160,7 @@ def collect(directory):
pictures.setdefault(kind, {})[screen] = path

for kind in SIZES:
missing = [screen for screen in SCREENS if screen not in pictures.get(kind, {})]
missing = [screen for screen in CAPTURED if screen not in pictures.get(kind, {})]
if missing:
problems.append(f"{locale}: no {kind} {', '.join(missing)}")

Expand All @@ -157,21 +169,24 @@ def collect(directory):
return found, problems


def stage(found, directory):
"""Write the screenshot tree deliver uploads.
def stage(found, directory, app):
"""Write the screenshot tree deliver uploads for `app`.

A folder per store locale, the borrowed ones copied from the English rather
than left out: what deliver does not upload for a locale, App Store Connect
keeps - which would be whatever was there before this release.
keeps - which would be whatever was there before this release. Lite's
pictures go under the name of the screen they replace, so they keep its
place in the store.
"""
directory = Path(directory)

for locale, pictures in found.items():
folder = directory / locale
folder.mkdir(parents=True, exist_ok=True)
for kind, screens in pictures.items():
for screen, path in screens.items():
shutil.copyfile(path, folder / f"{kind}-{screen}.png")
for screen in SCREENS:
picture = LITE.get(screen, screen) if app == "lite" else screen
shutil.copyfile(screens[picture], folder / f"{kind}-{screen}.png")

for locale in borrowed():
source = directory / FALLBACK
Expand Down Expand Up @@ -211,8 +226,16 @@ def main(argv=None):
metavar="DIR",
help="also write the deliver screenshot tree into DIR",
)
parser.add_argument(
"--app",
choices=APPS,
help="the app whose set --stage writes; the two differ in the edit",
)
args = parser.parse_args(argv)

if args.stage and not args.app:
parser.error("--stage needs --app, because Pro and Lite show a different edit")

if args.languages:
print("\n".join(languages()))
return 0
Expand All @@ -228,11 +251,11 @@ def main(argv=None):

if args.stage:
try:
stage(found, args.stage)
stage(found, args.stage, args.app)
except OSError as reason:
return fail(str(reason))
print(
f"staged {len(SCREENS)} screenshots per device for "
f"staged {args.app}'s {len(SCREENS)} screenshots per device for "
f"{len(found) + len(borrowed())} locales in {args.stage}"
)
else:
Expand Down
Loading