Files
native/app.config.js
T
Linus Rath bfa02f1177 feat: let the app rotate and work in landscape
The app was locked to portrait in app.config.js and the hand-kept
AndroidManifest.xml. Android 16 ignores that lock on screens 600 dp and
wider, so tablets and foldables rotated into layouts that were never
tested. This removes the lock in both places, keeps React state across
rotation and split-screen resizes (`smallestScreenSize` joins
`configChanges`), and fixes what broke in landscape:

- the thread pager sizes its pages from its own width and snaps back to
  the open message after a rotation instead of showing half a neighbour
- compose and the thread view share one keyboard tracker; a rotation
  with the keyboard open closes it, since Android sends no new keyboard
  frame and the old portrait one blanked the whole landscape composer
- in a short window with the keyboard up the composer hides the format
  bar and tightens its header so a few lines of text stay visible
- inputs with suggestions or context around them opt out of Android's
  full-screen landscape keyboard
- month views fit whole rows to the real height, keep the month across a
  remount, and the month dropdown re-measures and caps its height
- the week grid's header follows the remounted list after a rotation
- the event sheet's actions stay on screen in landscape
- every RN Modal allows all orientations, or iOS forces portrait
2026-10-15 01:45:23 +02:00

105 lines
3.4 KiB
JavaScript

const fs = require('node:fs');
const path = require('node:path');
const { execSync } = require('node:child_process');
const VERSION = fs.readFileSync(path.join(__dirname, 'VERSION'), 'utf8').trim();
let COMMIT = process.env.GITHUB_SHA || '';
if (!COMMIT) {
try {
COMMIT = execSync('git rev-parse --short HEAD', { cwd: __dirname, stdio: ['ignore', 'pipe', 'ignore'] })
.toString()
.trim();
} catch {
COMMIT = 'dev';
}
}
COMMIT = COMMIT.slice(0, 7);
// App Store Connect rejects a build whose CFBundleVersion it has already seen
// for this CFBundleShortVersionString, so this has to advance on every upload
// even when VERSION does not. CI passes the workflow run number; local builds
// fall back to 1 (never uploaded).
const IOS_BUILD_NUMBER = process.env.IOS_BUILD_NUMBER || '1';
module.exports = {
expo: {
name: 'Bulwark Mobile',
slug: 'bulwark-mobile',
// mailto: lets Android/iOS offer the app for mail links in other apps;
// bulwarkmail: is the webmail's sign-in link (bulwarkmail://pair?...).
// Android's manifest is maintained by hand and lists the same schemes.
scheme: ['bulwarkmobile', 'bulwarkmail', 'mailto'],
version: VERSION,
orientation: 'default',
icon: './assets/icon.png',
userInterfaceStyle: 'automatic',
newArchEnabled: true,
splash: {
image: './assets/splash-icon.png',
resizeMode: 'contain',
backgroundColor: '#ffffff',
dark: {
image: './assets/splash-icon.png',
backgroundColor: '#09090b',
},
},
ios: {
supportsTablet: true,
bundleIdentifier: 'org.bulwarkmail.mobile',
buildNumber: IOS_BUILD_NUMBER,
config: {
// The app only speaks HTTPS/TLS and uses platform crypto, which is
// exempt. Declaring it here skips the manual export-compliance
// questionnaire that otherwise blocks every TestFlight build.
usesNonExemptEncryption: false,
},
},
android: {
adaptiveIcon: {
foregroundImage: './assets/adaptive-icon.png',
backgroundColor: '#db2d54',
},
edgeToEdgeEnabled: true,
predictiveBackGestureEnabled: false,
package: 'com.anonymous.bulwarkmobile',
// The AsyncStorage database holds cached message bodies, the outbox and
// the account registry; the platform backup would ship all of it to the
// user's Google account. Credentials live in SecureStore (excluded by
// its own rules) but the mail cache must not leave the device either.
allowBackup: false,
},
web: {
favicon: './assets/favicon.png',
},
plugins: [
'expo-secure-store',
'@react-native-community/datetimepicker',
'expo-localization',
[
'expo-camera',
{
cameraPermission:
'Bulwark Mail uses the camera to scan sign-in QR codes shown in webmail.',
// QR scanning never records audio; leaving the mic entry in would be
// an unexplained permission in App Review.
microphonePermission: false,
},
],
[
'expo-image-picker',
{
photosPermission:
'Bulwark Mail needs access to your photos so you can attach them to emails and set contact photos.',
// Only launchImageLibraryAsync is used - no in-app capture.
cameraPermission: false,
microphonePermission: false,
},
],
],
extra: {
commit: COMMIT,
},
},
};