mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
chore(capacitor): base plugins
This commit is contained in:
@@ -62,7 +62,13 @@ captures/
|
||||
.cxx/
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
# google-services.json
|
||||
# Deliberately ignored: this file pins the build to one Firebase project.
|
||||
# Committing it would make every fork's builds register against the upstream
|
||||
# FCM project, and rotating the project would become a repo change. Official
|
||||
# builds inject it from a CI secret; see google-services.json.example.
|
||||
# app/build.gradle already tolerates its absence (push is simply inert).
|
||||
google-services.json
|
||||
app/google-services.json
|
||||
|
||||
# Freeline
|
||||
freeline.py
|
||||
|
||||
@@ -9,7 +9,24 @@ android {
|
||||
|
||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
|
||||
implementation project(':capacitor-app')
|
||||
implementation project(':capacitor-browser')
|
||||
implementation project(':capacitor-calendar')
|
||||
implementation project(':capacitor-camera')
|
||||
implementation project(':capacitor-file-transfer')
|
||||
implementation project(':capacitor-filesystem')
|
||||
implementation project(':capacitor-geolocation')
|
||||
implementation project(':capacitor-haptics')
|
||||
implementation project(':capacitor-inappbrowser')
|
||||
implementation project(':capacitor-keyboard')
|
||||
implementation project(':capacitor-local-notifications')
|
||||
implementation project(':capacitor-network')
|
||||
implementation project(':capacitor-preferences')
|
||||
implementation project(':capacitor-push-notifications')
|
||||
implementation project(':capacitor-share')
|
||||
implementation project(':capacitor-splash-screen')
|
||||
implementation project(':capacitor-status-bar')
|
||||
implementation project(':capacitor-toast')
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
@@ -22,6 +24,29 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- Deep links (@capacitor/app appUrlOpen).
|
||||
|
||||
The scheme is @string/custom_url_scheme (com.liketrek.trek).
|
||||
launchMode is singleTask above, so a link delivers into the
|
||||
running task via onNewIntent rather than starting a second copy
|
||||
of the app on top of the first.
|
||||
|
||||
This is the return path for native OIDC/OAuth login: the flow
|
||||
opens in a Custom Tab and the provider redirects back to
|
||||
com.liketrek.trek://… , which lands here.
|
||||
|
||||
Not an App Link (autoVerify + https). App Links are verified
|
||||
against a specific domain via assetlinks.json, and TREK is
|
||||
self-hosted — there is no single domain to verify against. A
|
||||
custom scheme is the only form that works for every user's
|
||||
server. -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="@string/custom_url_scheme" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
@@ -33,9 +58,102 @@
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths"></meta-data>
|
||||
</provider>
|
||||
|
||||
<!-- Notification icon, shared by @capacitor/push-notifications (via this
|
||||
FCM meta-data) and @capacitor/local-notifications (via the smallIcon
|
||||
option in capacitor.config.ts).
|
||||
|
||||
It must be a white silhouette on transparency; the launcher icon is a
|
||||
full-colour square and Android would render it as a white blob.
|
||||
notification_icon is generated from public/icons/icon-white.svg by
|
||||
scripts/generate-native-icons.mjs.
|
||||
|
||||
default_notification_channel_id names the channel FCM uses for any
|
||||
message that does not carry its own. The channel itself still has to
|
||||
be created at runtime with PushNotifications.createChannel() using
|
||||
this exact id — Android drops notifications for a channel that was
|
||||
never created, and FCM silently falls back to its own channel.
|
||||
|
||||
No default_notification_color on purpose. TREK's palette is neutral
|
||||
and user-selectable, so there is no one brand colour to tint with;
|
||||
left unset, Android tints the small icon with the system accent,
|
||||
which stays legible in both the light and dark shade. -->
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@drawable/notification_icon" />
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||
android:value="@string/default_notification_channel_id" />
|
||||
|
||||
<!-- Asks Play services to install the backported Android photo picker on
|
||||
Android 11/12 devices, so @capacitor/camera gets the modern picker
|
||||
instead of falling back to ACTION_OPEN_DOCUMENT. Disabled by design:
|
||||
it is a dependency declaration, not a service that runs.
|
||||
|
||||
Drop this block if TREK ever ships a Play-services-free build
|
||||
(F-Droid); the fallback picker keeps working without it. -->
|
||||
<service
|
||||
android:name="com.google.android.gms.metadata.ModuleDependencies"
|
||||
android:enabled="false"
|
||||
android:exported="false"
|
||||
tools:ignore="MissingClass">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="photopicker_activity:0:required" android:value="" />
|
||||
</service>
|
||||
</application>
|
||||
|
||||
<!-- Permissions -->
|
||||
<!-- Permissions.
|
||||
|
||||
Declared here only where the app itself needs them. Plugins that ship
|
||||
their own manifest contribute theirs through the merge and are NOT
|
||||
repeated: @capacitor/haptics (VIBRATE), @capacitor/calendar
|
||||
(READ_CALENDAR, WRITE_CALENDAR) and @capacitor/local-notifications
|
||||
(RECEIVE_BOOT_COMPLETED, WAKE_LOCK, SCHEDULE_EXACT_ALARM). -->
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!-- Reachability: connectivity.ts probes the server on an interval, and on
|
||||
native we want to skip the probe entirely when there is no transport.
|
||||
@capacitor/network declares this too; kept explicit because
|
||||
connectivity.ts depends on it directly. -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<!-- Android 13+ gates notifications behind a runtime grant. firebase-messaging
|
||||
and @capacitor/local-notifications declare this too, but relying on a
|
||||
transitive manifest merge for a permission the app must request by hand is
|
||||
a silent-failure waiting to happen — it must be requested via
|
||||
requestPermissions() before register()/schedule(). -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<!-- @capacitor/geolocation. Declares no permissions of its own, so both are
|
||||
required here. COARSE is listed first because it is the weaker grant and
|
||||
is enough for "what city am I in" — request FINE only where the map
|
||||
genuinely needs it. -->
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<!-- required="false" on purpose: TREK is a planner, and everything except
|
||||
"locate me" works without GPS hardware. Marking it required would have
|
||||
Play hide the app from tablets and other GPS-less devices. -->
|
||||
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
|
||||
|
||||
<!-- @capacitor/camera. Not strictly required — the plugin launches the system
|
||||
camera activity, which carries its own permission — but io.ionic.libs's
|
||||
inappbrowser transitively declares CAMERA anyway, and once it is declared
|
||||
Android routes the plugin through the runtime-grant path. Declared here
|
||||
explicitly so it is a decision rather than something inherited. -->
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<!-- Stripped from the merge. io.ionic.libs:ioninappbrowser-android declares
|
||||
RECORD_AUDIO and MODIFY_AUDIO_SETTINGS so that pages opened in its WebView
|
||||
mode can use getUserMedia for microphone capture. TREK records no audio
|
||||
anywhere, and shipping these would put "Microphone" on the store listing
|
||||
and in the app's permission screen for a capability that does not exist.
|
||||
|
||||
Revisit only if a feature genuinely needs mic input in an embedded page. -->
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" tools:node="remove" />
|
||||
|
||||
<!-- Deliberately NOT declared: READ/WRITE_EXTERNAL_STORAGE.
|
||||
@capacitor/camera needs storage permissions only for saveToGallery, and
|
||||
TREK uploads photos to the server rather than writing them to the device
|
||||
gallery. Add them the day a feature actually needs them. -->
|
||||
</manifest>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 491 B |
Binary file not shown.
|
After Width: | Height: | Size: 351 B |
Binary file not shown.
|
After Width: | Height: | Size: 597 B |
Binary file not shown.
|
After Width: | Height: | Size: 896 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -4,4 +4,8 @@
|
||||
<string name="title_activity_main">TREK - Plan your trips!</string>
|
||||
<string name="package_name">com.liketrek.trek</string>
|
||||
<string name="custom_url_scheme">com.liketrek.trek</string>
|
||||
<!-- Referenced by the FCM default_notification_channel_id meta-data in
|
||||
AndroidManifest.xml. A channel with this exact id must also be created
|
||||
at runtime via PushNotifications.createChannel(). -->
|
||||
<string name="default_notification_channel_id">trek_default</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
TREK is self-hosted: the user points the app at their own server, so we cannot
|
||||
know its scheme or its certificate authority ahead of time. Two deliberate
|
||||
relaxations, both required for that to work at all:
|
||||
|
||||
1. cleartextTrafficPermitted="true" — Android blocks http:// by default from
|
||||
targetSdk 28 on. A bare LAN server (http://192.168.1.10:3001) and a
|
||||
Tailscale host (100.64.0.0/10, which is NOT RFC1918, so a private-range
|
||||
allowlist would not cover it) both need this. https:// is unaffected and
|
||||
remains the recommended setup.
|
||||
|
||||
2. <certificates src="user" /> — since Android 7 apps ignore user-installed
|
||||
CAs unless they opt in. Self-hosters running their own CA (step-ca, mkcert,
|
||||
an internal PKI) install its root on the device; without this the app would
|
||||
reject their perfectly valid https:// server. System CAs stay first so
|
||||
public certs keep validating normally.
|
||||
|
||||
The tradeoff is that a user-installed CA can also be a MITM proxy's. That is
|
||||
the same tradeoff the browser-based PWA already makes, and it is the price of
|
||||
letting people run their own infrastructure.
|
||||
-->
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="true">
|
||||
<trust-anchors>
|
||||
<certificates src="system" />
|
||||
<certificates src="user" />
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
</network-security-config>
|
||||
@@ -1,3 +1,57 @@
|
||||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||
include ':capacitor-android'
|
||||
project(':capacitor-android').projectDir = new File('../../node_modules/@capacitor/android/capacitor')
|
||||
|
||||
include ':capacitor-app'
|
||||
project(':capacitor-app').projectDir = new File('../../node_modules/@capacitor/app/android')
|
||||
|
||||
include ':capacitor-browser'
|
||||
project(':capacitor-browser').projectDir = new File('../../node_modules/@capacitor/browser/android')
|
||||
|
||||
include ':capacitor-calendar'
|
||||
project(':capacitor-calendar').projectDir = new File('../../node_modules/@capacitor/calendar/android')
|
||||
|
||||
include ':capacitor-camera'
|
||||
project(':capacitor-camera').projectDir = new File('../../node_modules/@capacitor/camera/android')
|
||||
|
||||
include ':capacitor-file-transfer'
|
||||
project(':capacitor-file-transfer').projectDir = new File('../../node_modules/@capacitor/file-transfer/android')
|
||||
|
||||
include ':capacitor-filesystem'
|
||||
project(':capacitor-filesystem').projectDir = new File('../../node_modules/@capacitor/filesystem/android')
|
||||
|
||||
include ':capacitor-geolocation'
|
||||
project(':capacitor-geolocation').projectDir = new File('../../node_modules/@capacitor/geolocation/android')
|
||||
|
||||
include ':capacitor-haptics'
|
||||
project(':capacitor-haptics').projectDir = new File('../../node_modules/@capacitor/haptics/android')
|
||||
|
||||
include ':capacitor-inappbrowser'
|
||||
project(':capacitor-inappbrowser').projectDir = new File('../../node_modules/@capacitor/inappbrowser/android')
|
||||
|
||||
include ':capacitor-keyboard'
|
||||
project(':capacitor-keyboard').projectDir = new File('../../node_modules/@capacitor/keyboard/android')
|
||||
|
||||
include ':capacitor-local-notifications'
|
||||
project(':capacitor-local-notifications').projectDir = new File('../../node_modules/@capacitor/local-notifications/android')
|
||||
|
||||
include ':capacitor-network'
|
||||
project(':capacitor-network').projectDir = new File('../../node_modules/@capacitor/network/android')
|
||||
|
||||
include ':capacitor-preferences'
|
||||
project(':capacitor-preferences').projectDir = new File('../../node_modules/@capacitor/preferences/android')
|
||||
|
||||
include ':capacitor-push-notifications'
|
||||
project(':capacitor-push-notifications').projectDir = new File('../../node_modules/@capacitor/push-notifications/android')
|
||||
|
||||
include ':capacitor-share'
|
||||
project(':capacitor-share').projectDir = new File('../../node_modules/@capacitor/share/android')
|
||||
|
||||
include ':capacitor-splash-screen'
|
||||
project(':capacitor-splash-screen').projectDir = new File('../../node_modules/@capacitor/splash-screen/android')
|
||||
|
||||
include ':capacitor-status-bar'
|
||||
project(':capacitor-status-bar').projectDir = new File('../../node_modules/@capacitor/status-bar/android')
|
||||
|
||||
include ':capacitor-toast'
|
||||
project(':capacitor-toast').projectDir = new File('../../node_modules/@capacitor/toast/android')
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"_comment": [
|
||||
"Template only — this file is not read by the build.",
|
||||
"",
|
||||
"To enable Android push notifications:",
|
||||
" 1. Create a Firebase project at https://console.firebase.google.com",
|
||||
" 2. Add an Android app with package name com.liketrek.trek",
|
||||
" 3. Download the generated google-services.json",
|
||||
" 4. Place it at client/android/app/google-services.json (gitignored)",
|
||||
"",
|
||||
"Without it, app/build.gradle skips the google-services plugin and the app",
|
||||
"still builds and runs — PushNotifications.register() simply fails at runtime.",
|
||||
"",
|
||||
"The server that SENDS the notifications needs a service-account key from the",
|
||||
"SAME Firebase project. See docs for the self-hosting implications."
|
||||
],
|
||||
"project_info": {
|
||||
"project_number": "000000000000",
|
||||
"project_id": "your-firebase-project-id",
|
||||
"storage_bucket": "your-firebase-project-id.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:000000000000:android:0000000000000000000000",
|
||||
"android_client_info": {
|
||||
"package_name": "com.liketrek.trek"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "REPLACE_WITH_YOUR_ANDROID_API_KEY"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
ext {
|
||||
minSdkVersion = 24
|
||||
// 26, not Capacitor's default 24: @capacitor/inappbrowser requires a minimum
|
||||
// target of 26. This drops Android 7.0/7.1 (~1% of devices and no longer
|
||||
// receiving security updates). Removing @capacitor/inappbrowser — its system-
|
||||
// browser mode overlaps @capacitor/browser almost exactly — would allow 24
|
||||
// again.
|
||||
minSdkVersion = 26
|
||||
compileSdkVersion = 36
|
||||
targetSdkVersion = 36
|
||||
androidxActivityVersion = '1.11.0'
|
||||
@@ -13,4 +18,7 @@ ext {
|
||||
androidxJunitVersion = '1.3.0'
|
||||
androidxEspressoCoreVersion = '3.7.0'
|
||||
cordovaAndroidVersion = '14.0.1'
|
||||
// Consumed by @capacitor/push-notifications. Pinned rather than left to the
|
||||
// plugin's default so an FCM SDK bump is a visible, reviewable change here.
|
||||
firebaseMessagingVersion = '25.0.1'
|
||||
}
|
||||
@@ -1,9 +1,67 @@
|
||||
/// <reference types="@capacitor/push-notifications" />
|
||||
/// <reference types="@capacitor/local-notifications" />
|
||||
/// <reference types="@capacitor/splash-screen" />
|
||||
/// <reference types="@capacitor/keyboard" />
|
||||
import type { CapacitorConfig } from '@capacitor/cli';
|
||||
import { KeyboardResize } from '@capacitor/keyboard';
|
||||
|
||||
const config: CapacitorConfig = {
|
||||
appId: 'com.liketrek.trek',
|
||||
appName: 'TREK - Plan your trips!',
|
||||
webDir: 'dist'
|
||||
webDir: 'dist',
|
||||
// TREK is self-hosted: the server the app talks to is whatever the user
|
||||
// enters, so every request is cross-origin. Both schemes stay https so the
|
||||
// webview origin is a secure context (crypto.subtle, WebAuthn, service
|
||||
// workers, IndexedDB persistence all require it).
|
||||
server: {
|
||||
androidScheme: 'https',
|
||||
iosScheme: 'https',
|
||||
},
|
||||
plugins: {
|
||||
PushNotifications: {
|
||||
// No `badge`: TREK has no unread count the OS could keep honest, and a
|
||||
// badge that only ever grows is worse than none.
|
||||
presentationOptions: ['sound', 'banner', 'list'],
|
||||
},
|
||||
LocalNotifications: {
|
||||
// Same white-on-transparent mask as FCM uses; generated by
|
||||
// scripts/generate-native-icons.mjs. Without it Android falls back to the
|
||||
// launcher icon and renders a white blob.
|
||||
smallIcon: 'notification_icon',
|
||||
presentationOptions: ['sound', 'banner', 'list'],
|
||||
},
|
||||
SplashScreen: {
|
||||
// Matches <meta name="theme-color"> in index.html, so the launch image,
|
||||
// the splash and the first painted frame are the same colour and there is
|
||||
// no white flash between them.
|
||||
backgroundColor: '#09090b',
|
||||
launchShowDuration: 500,
|
||||
// Deliberately true. With `false` the splash stays up until JS calls
|
||||
// SplashScreen.hide(), and until that call exists a failure to boot the
|
||||
// bundle looks like a frozen app. Flip this to false — and drop
|
||||
// launchShowDuration — in the same change that adds the hide() call once
|
||||
// the React tree has mounted.
|
||||
launchAutoHide: true,
|
||||
launchFadeOutDuration: 200,
|
||||
showSpinner: false,
|
||||
androidScaleType: 'CENTER_CROP',
|
||||
},
|
||||
Keyboard: {
|
||||
// The mobile shell is built from bottom sheets (mobile/screens/**/M*Sheet).
|
||||
// `body` resizes the webview itself, so a sheet's own scroll container
|
||||
// keeps working; `native` resizes the whole view and fights the sheet.
|
||||
resize: KeyboardResize.Body,
|
||||
// Android-only workaround: with an edge-to-edge status bar the webview
|
||||
// otherwise does not resize at all when the keyboard opens.
|
||||
resizeOnFullScreen: true,
|
||||
// No `style`: TREK has a real appearance system, so the keyboard should
|
||||
// follow the device/app theme rather than being pinned here.
|
||||
},
|
||||
// No StatusBar block on purpose. From Android 15 / Capacitor 8 the app is
|
||||
// always edge-to-edge, so `overlaysWebView` and `backgroundColor` no longer
|
||||
// do anything. The status-bar style has to follow the user's chosen scheme
|
||||
// at runtime — call StatusBar.setStyle() from applyAppearance().
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
@@ -30,6 +30,14 @@ export default tseslint.config(
|
||||
'public',
|
||||
'test-results',
|
||||
'playwright-report',
|
||||
// Capacitor native shells. `npx cap sync` copies the built bundle from
|
||||
// dist/ into both platforms, so without these ESLint lints the minified
|
||||
// output and `npm run lint` reports tens of thousands of errors that have
|
||||
// nothing to do with the source. gitignore() does not cover them: the iOS
|
||||
// and Android .gitignore files live one level down, and this config's
|
||||
// gitignore integration only reads client/.gitignore.
|
||||
'android/**',
|
||||
'ios/**',
|
||||
'e2e/**',
|
||||
'scripts/**',
|
||||
'**/*.config.js',
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
|
||||
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
|
||||
9582B6832FE993A70072D4E8 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9582B6822FE993A50072D4E8 /* SceneDelegate.swift */; };
|
||||
7A1E00032C0000000000A003 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 7A1E00022C0000000000A002 /* PrivacyInfo.xcprivacy */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@@ -30,6 +31,8 @@
|
||||
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
|
||||
9582B6822FE993A50072D4E8 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
958DCC722DB07C7200EA8C5F /* debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = debug.xcconfig; path = ../debug.xcconfig; sourceTree = SOURCE_ROOT; };
|
||||
7A1E00012C0000000000A001 /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
|
||||
7A1E00022C0000000000A002 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -71,6 +74,8 @@
|
||||
504EC30E1FED79650016851F /* Assets.xcassets */,
|
||||
504EC3101FED79650016851F /* LaunchScreen.storyboard */,
|
||||
504EC3131FED79650016851F /* Info.plist */,
|
||||
7A1E00012C0000000000A001 /* App.entitlements */,
|
||||
7A1E00022C0000000000A002 /* PrivacyInfo.xcprivacy */,
|
||||
2FAD9762203C412B000D30F8 /* config.xml */,
|
||||
50B271D01FEDC1A000F3C39B /* public */,
|
||||
);
|
||||
@@ -113,6 +118,11 @@
|
||||
CreatedOnToolsVersion = 9.2;
|
||||
LastSwiftMigration = 1100;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.Push = {
|
||||
enabled = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -148,6 +158,7 @@
|
||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
|
||||
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
|
||||
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
|
||||
7A1E00032C0000000000A003 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -299,6 +310,7 @@
|
||||
baseConfigurationReference = 958DCC722DB07C7200EA8C5F /* debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
@@ -321,6 +333,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!--
|
||||
The Push Notifications capability. Xcode normally writes this when you tick
|
||||
"Push Notifications" under Signing & Capabilities; it is committed here so a
|
||||
clean checkout builds with push already enabled.
|
||||
|
||||
`development` is correct for debug builds and for TestFlight. Xcode's
|
||||
automatic signing rewrites this to `production` when archiving for
|
||||
distribution, so it does not need a second value here.
|
||||
|
||||
Enabling the capability in the Apple Developer portal for the App ID
|
||||
com.liketrek.trek is a separate, manual step — the entitlement alone will
|
||||
fail to sign until the App ID has it too.
|
||||
-->
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -33,6 +33,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
// MARK: - Push notifications
|
||||
//
|
||||
// @capacitor/push-notifications does not swizzle the APNs callbacks; it listens
|
||||
// on NotificationCenter instead, so these two forwarders are mandatory. Without
|
||||
// them PushNotifications.register() resolves and then nothing ever arrives —
|
||||
// neither the `registration` nor the `registrationError` listener fires, which
|
||||
// makes it look like a server problem rather than a missing 6 lines here.
|
||||
|
||||
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
||||
NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
|
||||
NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication,
|
||||
configurationForConnecting connectingSceneSession: UISceneSession,
|
||||
options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
||||
|
||||
@@ -24,6 +24,84 @@
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<!-- TREK is self-hosted: the user types in their own server address, so the
|
||||
app cannot know its scheme, hostname or certificate authority at build
|
||||
time. NSAllowsArbitraryLoads is the only ATS setting that covers all of
|
||||
https://trek.example.com, http://192.168.1.10:3001 and a Tailscale host
|
||||
on 100.64.0.0/10 (which is NOT RFC1918, so NSAllowsLocalNetworking alone
|
||||
would not reach it).
|
||||
|
||||
Deliberately the ONLY key in this dict. From iOS 10 on, the presence of
|
||||
NSAllowsLocalNetworking, NSAllowsArbitraryLoadsInWebContent or
|
||||
NSAllowsArbitraryLoadsForMedia makes the system IGNORE
|
||||
NSAllowsArbitraryLoads — adding one of them "to be safe" would silently
|
||||
re-block every cleartext server outside the local subnet.
|
||||
|
||||
App Review will ask for a justification; the answer is that the app is a
|
||||
client for a server the user hosts and names themselves. https remains
|
||||
the documented recommendation for anything past a LAN. -->
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<!-- Local Network Privacy is a separate gate from ATS: since iOS 14 any
|
||||
connection to a local-network address prompts the user, and no ATS key
|
||||
waives it. Without this string the prompt has no explanation and iOS
|
||||
logs "Local network prohibited" instead of a useful error. -->
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>TREK connects to the TREK server you choose, which is often running on your home or office network.</string>
|
||||
<!-- Permission usage descriptions. iOS does not merely deny a missing one —
|
||||
it terminates the app the first time the API is touched, so every key
|
||||
below is load-bearing even where the feature is optional.
|
||||
|
||||
@capacitor/camera -->
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>TREK uses the camera so you can photograph a place, a journey entry or a booking document and add it to your trip.</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>TREK needs access to your photos so you can add them to trips, places and journey entries.</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>TREK saves photos and exports you download from your trips back to your photo library.</string>
|
||||
<!-- @capacitor/geolocation. NSLocationAlwaysAndWhenInUse is required by
|
||||
Apple because the underlying ion-ios-geolocation library is capable of
|
||||
background reporting; TREK never asks for it, so the user only ever sees
|
||||
the when-in-use prompt. -->
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>TREK uses your location to centre the map on you and to find places near you.</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>TREK uses your location to centre the map on you and to find places near you.</string>
|
||||
<!-- @capacitor/calendar. iOS 17 split calendar access into full and
|
||||
write-only, each with its own key; the pre-17 key stays for older
|
||||
devices. Adding a trip to the device calendar needs only write-only
|
||||
access, which is the weaker prompt. -->
|
||||
<key>NSCalendarsWriteOnlyAccessUsageDescription</key>
|
||||
<string>TREK adds your trip days and bookings to your calendar.</string>
|
||||
<key>NSCalendarsFullAccessUsageDescription</key>
|
||||
<string>TREK reads your calendar to show existing commitments alongside your trip, and adds trip events to it.</string>
|
||||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>TREK adds your trip days and bookings to your calendar.</string>
|
||||
<!-- Deep links (@capacitor/app appUrlOpen), matching the intent-filter in
|
||||
AndroidManifest.xml and @string/custom_url_scheme there. This is the
|
||||
return path for native OIDC/OAuth login, which opens in an
|
||||
SFSafariViewController and redirects back to com.liketrek.trek://…
|
||||
|
||||
Not a Universal Link: those are verified against one specific domain via
|
||||
apple-app-site-association, and a self-hosted app has no single domain to
|
||||
verify against. SceneDelegate already forwards openURLContexts to
|
||||
Capacitor, so no Swift change is needed. -->
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.liketrek.trek</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>com.liketrek.trek</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!--
|
||||
Apple's required-reason API declaration. App Store Connect rejects uploads
|
||||
that call these APIs without an entry here.
|
||||
|
||||
NSPrivacyAccessedAPICategoryFileTimestamp / C617.1 is required by
|
||||
@capacitor/filesystem, which @capacitor/file-transfer depends on to resolve
|
||||
a native path before it can download or upload. Capacitor's own frameworks
|
||||
ship their own PrivacyInfo; this file covers the app target only.
|
||||
|
||||
Add to this file when adding a plugin that touches a required-reason API —
|
||||
UserDefaults (CA92.1) for @capacitor/preferences, disk space (E174.1),
|
||||
system boot time (35F9.1).
|
||||
-->
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>C617.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<!-- @capacitor/preferences, which backs the saved server profiles. -->
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>CA92.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<!-- TREK sends no data to third parties and runs no trackers: all traffic
|
||||
goes to the server the user chose. -->
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -11,14 +11,50 @@ let package = Package(
|
||||
targets: ["CapApp-SPM"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "8.5.0")
|
||||
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "8.5.0"),
|
||||
.package(name: "CapacitorApp", path: "../../../../node_modules/@capacitor/app"),
|
||||
.package(name: "CapacitorBrowser", path: "../../../../node_modules/@capacitor/browser"),
|
||||
.package(name: "CapacitorCalendar", path: "../../../../node_modules/@capacitor/calendar"),
|
||||
.package(name: "CapacitorCamera", path: "../../../../node_modules/@capacitor/camera"),
|
||||
.package(name: "CapacitorFileTransfer", path: "../../../../node_modules/@capacitor/file-transfer"),
|
||||
.package(name: "CapacitorFilesystem", path: "../../../../node_modules/@capacitor/filesystem"),
|
||||
.package(name: "CapacitorGeolocation", path: "../../../../node_modules/@capacitor/geolocation"),
|
||||
.package(name: "CapacitorHaptics", path: "../../../../node_modules/@capacitor/haptics"),
|
||||
.package(name: "CapacitorInappbrowser", path: "../../../../node_modules/@capacitor/inappbrowser"),
|
||||
.package(name: "CapacitorKeyboard", path: "../../../../node_modules/@capacitor/keyboard"),
|
||||
.package(name: "CapacitorLocalNotifications", path: "../../../../node_modules/@capacitor/local-notifications"),
|
||||
.package(name: "CapacitorNetwork", path: "../../../../node_modules/@capacitor/network"),
|
||||
.package(name: "CapacitorPreferences", path: "../../../../node_modules/@capacitor/preferences"),
|
||||
.package(name: "CapacitorPushNotifications", path: "../../../../node_modules/@capacitor/push-notifications"),
|
||||
.package(name: "CapacitorShare", path: "../../../../node_modules/@capacitor/share"),
|
||||
.package(name: "CapacitorSplashScreen", path: "../../../../node_modules/@capacitor/splash-screen"),
|
||||
.package(name: "CapacitorStatusBar", path: "../../../../node_modules/@capacitor/status-bar"),
|
||||
.package(name: "CapacitorToast", path: "../../../../node_modules/@capacitor/toast")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "CapApp-SPM",
|
||||
dependencies: [
|
||||
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
||||
.product(name: "Cordova", package: "capacitor-swift-pm")
|
||||
.product(name: "Cordova", package: "capacitor-swift-pm"),
|
||||
.product(name: "CapacitorApp", package: "CapacitorApp"),
|
||||
.product(name: "CapacitorBrowser", package: "CapacitorBrowser"),
|
||||
.product(name: "CapacitorCalendar", package: "CapacitorCalendar"),
|
||||
.product(name: "CapacitorCamera", package: "CapacitorCamera"),
|
||||
.product(name: "CapacitorFileTransfer", package: "CapacitorFileTransfer"),
|
||||
.product(name: "CapacitorFilesystem", package: "CapacitorFilesystem"),
|
||||
.product(name: "CapacitorGeolocation", package: "CapacitorGeolocation"),
|
||||
.product(name: "CapacitorHaptics", package: "CapacitorHaptics"),
|
||||
.product(name: "CapacitorInappbrowser", package: "CapacitorInappbrowser"),
|
||||
.product(name: "CapacitorKeyboard", package: "CapacitorKeyboard"),
|
||||
.product(name: "CapacitorLocalNotifications", package: "CapacitorLocalNotifications"),
|
||||
.product(name: "CapacitorNetwork", package: "CapacitorNetwork"),
|
||||
.product(name: "CapacitorPreferences", package: "CapacitorPreferences"),
|
||||
.product(name: "CapacitorPushNotifications", package: "CapacitorPushNotifications"),
|
||||
.product(name: "CapacitorShare", package: "CapacitorShare"),
|
||||
.product(name: "CapacitorSplashScreen", package: "CapacitorSplashScreen"),
|
||||
.product(name: "CapacitorStatusBar", package: "CapacitorStatusBar"),
|
||||
.product(name: "CapacitorToast", package: "CapacitorToast")
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"prebuild": "node scripts/generate-icons.mjs",
|
||||
"icons:native": "node scripts/generate-native-icons.mjs",
|
||||
"build": "vite build",
|
||||
"build:analyze": "vite build --mode analyze",
|
||||
"preview": "vite preview",
|
||||
@@ -30,8 +31,26 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@capacitor/android": "^8.5.0",
|
||||
"@capacitor/app": "^8.1.1",
|
||||
"@capacitor/browser": "^8.0.4",
|
||||
"@capacitor/calendar": "^1.0.1",
|
||||
"@capacitor/camera": "^8.2.3",
|
||||
"@capacitor/core": "^8.5.0",
|
||||
"@capacitor/file-transfer": "^2.0.5",
|
||||
"@capacitor/filesystem": "^8.1.3",
|
||||
"@capacitor/geolocation": "^8.2.2",
|
||||
"@capacitor/haptics": "^8.0.2",
|
||||
"@capacitor/inappbrowser": "^4.0.3",
|
||||
"@capacitor/ios": "^8.5.0",
|
||||
"@capacitor/keyboard": "^8.0.5",
|
||||
"@capacitor/local-notifications": "^8.3.1",
|
||||
"@capacitor/network": "^8.0.1",
|
||||
"@capacitor/preferences": "^8.0.1",
|
||||
"@capacitor/push-notifications": "^8.1.2",
|
||||
"@capacitor/share": "^8.0.1",
|
||||
"@capacitor/splash-screen": "^8.0.2",
|
||||
"@capacitor/status-bar": "^8.0.3",
|
||||
"@capacitor/toast": "^8.0.1",
|
||||
"@fontsource/bebas-neue": "^5.3.0",
|
||||
"@fontsource/eb-garamond": "^5.3.0",
|
||||
"@fontsource/geist-sans": "^5.2.5",
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Generates the Android status-bar notification icon from the master
|
||||
* white-silhouette SVG.
|
||||
*
|
||||
* Android renders the small notification icon as a mask: every non-transparent
|
||||
* pixel becomes the tint colour and everything else is dropped. Feeding it the
|
||||
* launcher icon (a full-bleed coloured square) therefore produces a solid white
|
||||
* blob, which is the single most common Capacitor push-notification complaint.
|
||||
* public/icons/icon-white.svg is already white-on-transparent, so we only have
|
||||
* to rasterise it at the five densities and flatten the colour to pure white so
|
||||
* any future edit to that SVG's fill cannot silently change the mask.
|
||||
*
|
||||
* Referenced from AndroidManifest.xml as @drawable/notification_icon.
|
||||
* Run: node scripts/generate-native-icons.mjs
|
||||
*/
|
||||
import { mkdirSync } from 'fs';
|
||||
import { dirname, join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import sharp from 'sharp';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const clientDir = join(__dirname, '..');
|
||||
const source = join(clientDir, 'public', 'icons', 'icon-white.svg');
|
||||
const resDir = join(clientDir, 'android', 'app', 'src', 'main', 'res');
|
||||
|
||||
// Android notification icon sizes, in px, per density bucket (24dp baseline).
|
||||
const densities = [
|
||||
{ dir: 'drawable-mdpi', size: 24 },
|
||||
{ dir: 'drawable-hdpi', size: 36 },
|
||||
{ dir: 'drawable-xhdpi', size: 48 },
|
||||
{ dir: 'drawable-xxhdpi', size: 72 },
|
||||
{ dir: 'drawable-xxxhdpi', size: 96 },
|
||||
];
|
||||
|
||||
for (const { dir, size } of densities) {
|
||||
const outDir = join(resDir, dir);
|
||||
mkdirSync(outDir, { recursive: true });
|
||||
|
||||
// Inset the glyph slightly: Android's status bar clips tight to the 24dp box
|
||||
// and a mark that touches the edge reads as cropped.
|
||||
const glyph = Math.round(size * 0.86);
|
||||
|
||||
const mask = await sharp(source, { density: 512 })
|
||||
.resize(glyph, glyph, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
|
||||
.extend({
|
||||
top: Math.floor((size - glyph) / 2),
|
||||
bottom: Math.ceil((size - glyph) / 2),
|
||||
left: Math.floor((size - glyph) / 2),
|
||||
right: Math.ceil((size - glyph) / 2),
|
||||
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
||||
})
|
||||
.ensureAlpha()
|
||||
.toBuffer();
|
||||
|
||||
// Keep the alpha, force every visible pixel to pure white. `dest-in` composites
|
||||
// the white plate through the glyph's alpha channel.
|
||||
await sharp({
|
||||
create: { width: size, height: size, channels: 4, background: { r: 255, g: 255, b: 255, alpha: 1 } },
|
||||
})
|
||||
.composite([{ input: mask, blend: 'dest-in' }])
|
||||
.png({ compressionLevel: 9 })
|
||||
.toFile(join(outDir, 'notification_icon.png'));
|
||||
|
||||
console.log(` ✓ ${dir}/notification_icon.png (${size}x${size})`);
|
||||
}
|
||||
|
||||
console.log('Android notification icons generated.');
|
||||
Generated
+195
@@ -28,8 +28,26 @@
|
||||
"version": "3.4.1",
|
||||
"dependencies": {
|
||||
"@capacitor/android": "^8.5.0",
|
||||
"@capacitor/app": "^8.1.1",
|
||||
"@capacitor/browser": "^8.0.4",
|
||||
"@capacitor/calendar": "^1.0.1",
|
||||
"@capacitor/camera": "^8.2.3",
|
||||
"@capacitor/core": "^8.5.0",
|
||||
"@capacitor/file-transfer": "^2.0.5",
|
||||
"@capacitor/filesystem": "^8.1.3",
|
||||
"@capacitor/geolocation": "^8.2.2",
|
||||
"@capacitor/haptics": "^8.0.2",
|
||||
"@capacitor/inappbrowser": "^4.0.3",
|
||||
"@capacitor/ios": "^8.5.0",
|
||||
"@capacitor/keyboard": "^8.0.5",
|
||||
"@capacitor/local-notifications": "^8.3.1",
|
||||
"@capacitor/network": "^8.0.1",
|
||||
"@capacitor/preferences": "^8.0.1",
|
||||
"@capacitor/push-notifications": "^8.1.2",
|
||||
"@capacitor/share": "^8.0.1",
|
||||
"@capacitor/splash-screen": "^8.0.2",
|
||||
"@capacitor/status-bar": "^8.0.3",
|
||||
"@capacitor/toast": "^8.0.1",
|
||||
"@fontsource/bebas-neue": "^5.3.0",
|
||||
"@fontsource/eb-garamond": "^5.3.0",
|
||||
"@fontsource/geist-sans": "^5.2.5",
|
||||
@@ -2379,6 +2397,42 @@
|
||||
"@capacitor/core": "^8.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/app": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/app/-/app-8.1.1.tgz",
|
||||
"integrity": "sha512-xM2ZTX5jK60tFtmjsmJv+Cdj1Qsb6NcavkqmdEnCPQBeya9oKhamZJxYOnQNj1ZvcJM7sWfG6BEtSLx42pisbA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/browser": {
|
||||
"version": "8.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/browser/-/browser-8.0.4.tgz",
|
||||
"integrity": "sha512-ORZ4u/y+7aMuu6yVuk6SP529fUZyqcbnuHB1q5McpA3o2SYfVoi28iB8rsQjI2ad1qlKJd29ZUuGtspXLBDlWg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/calendar": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/calendar/-/calendar-1.0.1.tgz",
|
||||
"integrity": "sha512-2ogW+Jlamy6BJkZmaggB/Jx282G+o3aBPfgx3GxmjlLjl8hqcorQKFhlCiveDui6xEKoVy13AQpKhukHQ8MrCQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/camera": {
|
||||
"version": "8.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/camera/-/camera-8.2.3.tgz",
|
||||
"integrity": "sha512-x9Pl5UgvrZyU5Hl53Fly9f6u019hhgN+gSdDgi+WygxK9DUVuYKjigplOXz3VJQ9m8ttUSjqN/rAC3JVnyEzcA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/cli": {
|
||||
"version": "8.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-8.5.0.tgz",
|
||||
@@ -2503,6 +2557,60 @@
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/file-transfer": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/file-transfer/-/file-transfer-2.0.5.tgz",
|
||||
"integrity": "sha512-G2a/+NKvADNcmxMSqy6HPp+Ij3trCy0+EVNMrRWmp8ueyCNaJEi96LpfEIztv+vqK9+xLRskQ7iVl+Pj8qt4hg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@capacitor/synapse": "^1.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/filesystem": {
|
||||
"version": "8.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-8.1.3.tgz",
|
||||
"integrity": "sha512-GNBlRkaXEEb+6WP/YsDXr2zygyOHoieuye6viyd2ZkEdBwfseG41jxfarVxLWH0r0owhyNUbwJ/Qi8fubqr6wA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@capacitor/synapse": "^1.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/geolocation": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/geolocation/-/geolocation-8.2.2.tgz",
|
||||
"integrity": "sha512-X8ryw6CfL4LspJnnfVL4++DUKKZVfdUIA9JljWVRljEDIQxZQZtz6xf7qstht+ymc+le6oa5EaUChVA6KsCYlA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@capacitor/synapse": "^1.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/haptics": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-8.0.2.tgz",
|
||||
"integrity": "sha512-c2hZzRR5Fk1tbTvhG1jhh2XBAf3EhnIerMIb2sl7Mt41Gxx1fhBJFDa0/BI1IbY4loVepyyuqNC9820/GZuoWQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/inappbrowser": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/inappbrowser/-/inappbrowser-4.0.3.tgz",
|
||||
"integrity": "sha512-Jnl6Ssp2QZByncO6QhDKzNpi3yeum1aSQM+70VMVh8TJ16HOwOrcTnf8E4+7FpT9ruSRGyhqQu1yBSrpl+wD1g==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/ios": {
|
||||
"version": "8.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-8.5.0.tgz",
|
||||
@@ -2512,6 +2620,93 @@
|
||||
"@capacitor/core": "^8.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/keyboard": {
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-8.0.5.tgz",
|
||||
"integrity": "sha512-oFXygC4eKYA5l2MdpTR06L2M/4x6e2SLD5yS1T9+UBDKTkzyvhWKEhbYLUaTIBPpLKqlfGudJw1X73S1H9eUzQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/local-notifications": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/local-notifications/-/local-notifications-8.3.1.tgz",
|
||||
"integrity": "sha512-F7zu/+p/mIR958YP4axOkeI5hBKRaXDyYjbNPrAil2wWfd7OxScPSTvP9t85NpQ0eULVRu0/sntoxOg6ck477A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/network": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/network/-/network-8.0.1.tgz",
|
||||
"integrity": "sha512-9xK/FHFmzKGanB6BdoSZOzXk8vF0OFVQSQ4PAsIrzAzLuXHryO317qy8dcHVpgxYeuZq2noI0My9z1DvVDi/9w==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/preferences": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/preferences/-/preferences-8.0.1.tgz",
|
||||
"integrity": "sha512-T6no3ebi79XJCk91U3Jp/liJUwgBdvHR+s6vhvPkPxSuch7z3zx5Rv1bdWM6sWruNx+pViuEGqZvbfCdyBvcHQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/push-notifications": {
|
||||
"version": "8.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/push-notifications/-/push-notifications-8.1.2.tgz",
|
||||
"integrity": "sha512-TQl4XxqJfNF+KbSYBFMXYYT5WXUaleVKXlByhh/8+KySMVNjp+l5OqAUoGe/sY1IAnGXEuUeCjA/WLZEVvGwrA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/share": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/share/-/share-8.0.1.tgz",
|
||||
"integrity": "sha512-3cSBKBCJVon54rKDROP2rqGyeGks4pBh9TbaEk9S375Kbek/ZHe72N50zIa0Vn9Eac/SuhwgehO/mmA4CsUOiw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/splash-screen": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/splash-screen/-/splash-screen-8.0.2.tgz",
|
||||
"integrity": "sha512-0C6rYScr13WfAE9nPl4ScOQynmjFv9NT3Th+RZkD4ezYHmER6mcl1/lDYsv7jg3Rj3FOvLrlTlmNkUrr83kZzQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/status-bar": {
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-8.0.3.tgz",
|
||||
"integrity": "sha512-csSpfNeN49Hx9JaQBSJEIiEbOLtXg3kcc2IpScq2fu5L520h3AWEvsxoH8Srk1jxfRKepaJ4S4sqSC3foI4AgA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/synapse": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/synapse/-/synapse-1.0.4.tgz",
|
||||
"integrity": "sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@capacitor/toast": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/toast/-/toast-8.0.1.tgz",
|
||||
"integrity": "sha512-0uoyftoAeFjtOMiozBo7YXEo+zcpQCAxtBONSvrljJ05SKdlb1A8OFHaV/DZfIpGt+19kzUGaEaUemLdll4wUw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@csstools/color-helpers": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz",
|
||||
|
||||
Reference in New Issue
Block a user