Skip to content

Commit

Permalink
feat(#687): add script to generate screencasts
Browse files Browse the repository at this point in the history
  • Loading branch information
tamslo committed Mar 5, 2024
1 parent 48d116a commit 9f3176c
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 4 deletions.
11 changes: 9 additions & 2 deletions app/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,19 @@ flutter pub run flutter_launcher_icons:main

This will generate icons for both iOS as well as Android.

## Updating screenshots
## Updating screencast and screenshots

🙅 _Not working yet due to login redirect, but keeping script for Sinai_
_version (login without redirect)._

To update the screenshots in `../docs/screenshots`
The `generate_screenshots/generate_screencast.sh` script will create screenshots
and screencasts. It uses Xcode to record the screencast and
[`ffmpeg`](https://ffmpeg.org/)
to cut the `full.mov` to relevant subsets.

Run the script with `bash generate_screenshots/generate_screencast.sh`.

To only update the screenshots in `../docs/screenshots`
(used in [📑 App screens](../docs/App-screens.md),
[📑 User instructions](../docs/User-instructions.html), and the
[README](./README.md)), run the following command after adding username and
Expand Down
14 changes: 12 additions & 2 deletions app/generate_screenshots/app_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import 'dart:io';

import 'package:app/app.dart';
import 'package:app/common/module.dart';
import 'package:dartx/dartx_io.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:provider/provider.dart';


Future<void> takeScreenshot(
WidgetTester tester,
IntegrationTestWidgetsFlutterBinding binding,
Expand All @@ -22,6 +22,12 @@ Future<void> takeScreenshot(
await binding.takeScreenshot(fileName);
}

void logTimeStamp(String description) {
final timestamp = DateTime.now().millisecondsSinceEpoch;
// ignore: avoid_print
print('TIMESTAMP: $timestamp $description');
}

void main() {
group('click through the app and create screenshots', () {
final binding = IntegrationTestWidgetsFlutterBinding();
Expand All @@ -45,12 +51,16 @@ void main() {
);
await tester.pumpAndSettle();

logTimeStamp('test_start');

// Click though the app and create screenshots

// login
await Future.delayed(Duration(seconds: 1)); // wait for logo
await Future.delayed(Duration(seconds: 5)); // wait for logo & screencast
await takeScreenshot(tester, binding, 'login');

logTimeStamp('login');

// login-redirect (not working; only taking screenshot of loading screen)
// could try to use cubit function to directly sign in which will only
// open the webview and close it again
Expand Down
96 changes: 96 additions & 0 deletions app/generate_screenshots/generate_screencast.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/bin/bash

output_directory="../docs/screencasts/"
cuts_log_path="${output_directory}cuts.log"
test_log_path="${output_directory}test.log"
full_video_path="${output_directory}full.mov"

read -p "Enter username: " username
read -p "Enter password: " password

log_timestamp() {
echo "$(date +%s000) $1" >> "$cuts_log_path"
}

# Doing the recording inspired by
# https://betterprogramming.pub/how-to-record-flutter-integration-tests-with-github-actions-1ca670eff94a

# Start recording


rm "$cuts_log_path"
xcrun simctl io booted recordVideo "$full_video_path" -f &
log_timestamp "recording_start"
sleep 5
export RECORDING_PID=${!}
echo "Recording process up with pid: ${RECORDING_PID}"
echo "Running app"
flutter drive \
--driver=generate_screenshots/test_driver.dart \
--target=generate_screenshots/app_test.dart \
--dart-define=TEST_USER="$username" \
--dart-define=TEST_PASSWORD="$password" > "$test_log_path"

# Write cut timestamps from test.log to cut.log

echo "Finishing recording"
timestamp_prefix="flutter: TIMESTAMP: "
extracted_timestamps=$(\
awk -v s="$timestamp_prefix" 'index($0, s) == 1' "$test_log_path" | \
sed -e "s/^$timestamp_prefix//"\
)
echo "$extracted_timestamps" >> "$cuts_log_path"
rm "$test_log_path"

# End recording

log_timestamp "recording_end"
sleep 5
kill -SIGINT $RECORDING_PID
sleep 10
echo ""

# Cut smaller screencasts

echo "Cutting smaller screencasts"
timestamps=()
descriptions=()
while read cut_info; do
cut_info_array=($cut_info)
timestamp=${cut_info_array[0]}
description=${cut_info_array[1]}
timestamps+=("$timestamp")
descriptions+=("$description")
done < "$cuts_log_path"

get_seconds_since_start() {
echo $((($1-${timestamps[0]})/1000))
}

# Format seconds as hh:mm:ss, see https://stackoverflow.com/a/13425821
format_seconds_as_time() {
((
sec=$1%60,
$1/=60,
min=$1%60,
hrs=$1/60
))
echo $(printf "%02d:%02d:%02d" $hrs $min $sec)
}

for ((i=2; i<${#timestamps[@]}-1; i++))
do
description=${descriptions[i]}
echo "Cutting $description"
start_seconds=$(get_seconds_since_start ${timestamps[i-1]})
end_seconds=$(get_seconds_since_start ${timestamps[i]})
start_time=$(format_seconds_as_time start_seconds)
end_time=$(format_seconds_as_time end_seconds)
## Use ffmpeg to cut, see https://stackoverflow.com/a/42827058
video_path="${output_directory}${description}.mov"
ffmpeg -y -loglevel error \
-ss "$start_time" \
-to "$end_time" \
-i "$full_video_path" \
-c copy "$video_path"
done

0 comments on commit 9f3176c

Please sign in to comment.