Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2387fa9bd7 | ||
|
|
91b88cd443 | ||
|
|
a1f6fbc2ec | ||
|
|
fed9abc5b8 | ||
|
|
b368b0bfcb | ||
|
|
2fa8c2b809 | ||
|
|
be399fdb3b | ||
|
|
2927e09799 | ||
|
|
ec4f114b82 | ||
|
|
9a524549b7 | ||
|
|
4a3899c098 | ||
|
|
4eb10b7794 | ||
|
|
bc6856f7d3 | ||
|
|
fa4397d502 | ||
|
|
ace454934c | ||
|
|
581ce227c6 | ||
|
|
a619addd70 | ||
|
|
87797617d7 | ||
|
|
7fb7fb0acf | ||
|
|
90dfa7aa55 | ||
|
|
20e7914cad | ||
|
|
a8393fcfe8 | ||
|
|
c2cfc1e287 | ||
|
|
e650417b40 | ||
|
|
2e57a4fee8 | ||
|
|
93491ad59d | ||
|
|
b90eed0c0c | ||
|
|
1ccbdb4855 | ||
|
|
b20ef67eda | ||
|
|
9e43cce27f | ||
|
|
3740876bc7 | ||
|
|
55e55e598f | ||
|
|
f42cee7428 | ||
|
|
59b1997c34 | ||
|
|
bfb8838d5d | ||
|
|
006142cd7a | ||
|
|
79d464943b | ||
|
|
6f034e11f1 | ||
|
|
9b15ea96f6 | ||
|
|
d7626845d9 | ||
|
|
bf2154da14 | ||
|
|
0f41412dba | ||
|
|
841803b2d4 | ||
|
|
a6d6b1dff8 | ||
|
|
fee9e88c13 | ||
|
|
0cff8edfcd | ||
|
|
b4fe28fa00 | ||
|
|
72da275f24 | ||
|
|
b86291107e | ||
|
|
bce28777d1 | ||
|
|
bf0d5383ab | ||
|
|
4997e975ac | ||
|
|
ed020d236b | ||
|
|
92cae40eab | ||
|
|
f76b3eb281 | ||
|
|
0ec44e86e4 | ||
|
|
6d990ea663 | ||
|
|
9d96dfbd68 | ||
|
|
dca3987857 | ||
|
|
fc16d69ba6 | ||
|
|
bf11a17a81 | ||
|
|
b3c6210ffc | ||
|
|
d3df63fbb2 | ||
|
|
057c6bd978 | ||
|
|
3fbc237fd6 | ||
|
|
6603ab3215 | ||
|
|
9f49f02401 | ||
|
|
14dc560092 | ||
|
|
2dcaff6772 | ||
|
|
68190997b6 | ||
|
|
74f55fc342 | ||
|
|
e32378e8ed | ||
|
|
764a04710b | ||
|
|
837602af36 | ||
|
|
af22acc509 | ||
|
|
994fadc8dd | ||
|
|
987b109e46 | ||
|
|
226b2a6412 | ||
|
|
d1a2929130 | ||
|
|
a04de8a0e0 | ||
|
|
20a4ecf8a8 | ||
|
|
9e8a90d523 | ||
|
|
9c79b293d8 | ||
|
|
77eb67c5b6 | ||
|
|
190c489b76 | ||
|
|
6c898afd0e | ||
|
|
b55b04d5fd | ||
|
|
0c7b413a76 | ||
|
|
731c5b07b4 | ||
|
|
96c72dda46 | ||
|
|
29ee948c98 | ||
|
|
2fc8f5a3bc | ||
|
|
7a570fb05a | ||
|
|
aed09045d6 | ||
|
|
ad810c8b11 | ||
|
|
e445cb4bc8 | ||
|
|
9b22a71343 | ||
|
|
e49a241243 | ||
|
|
2e06dcae54 | ||
|
|
a24ea1df58 | ||
|
|
50646306c5 | ||
|
|
6fbb2192ad | ||
|
|
7c3cda4f79 | ||
|
|
a78e569f54 | ||
|
|
3fee1c0e6e | ||
|
|
31aee40ee3 | ||
|
|
21c49280d4 | ||
|
|
ce1a818564 | ||
|
|
241d378a54 | ||
|
|
d1bf616248 | ||
|
|
a99c60efd5 | ||
|
|
331ecb163f | ||
|
|
1003ddb2ec | ||
|
|
5ca4e44a49 | ||
|
|
4103b4eb7d | ||
|
|
f8023bf04c | ||
|
|
1b3e87f930 | ||
|
|
5e3ed6d5e4 | ||
|
|
f46f340623 | ||
|
|
99f18da4ed | ||
|
|
999cc00275 | ||
|
|
363d36b0bb | ||
|
|
37d11f1867 | ||
|
|
7ecaaf5bd9 | ||
|
|
9ff7299176 | ||
|
|
f1bd9a7e27 | ||
|
|
83b52a3b61 | ||
|
|
16dfad4dc8 | ||
|
|
0f6493e28d | ||
|
|
0d55f9c8c9 | ||
|
|
fa85f7cf36 | ||
|
|
28997c1062 | ||
|
|
d6050beb2a | ||
|
|
5f4e90059e | ||
|
|
c3a375b292 | ||
|
|
1648e8598b | ||
|
|
e2d2b27494 | ||
|
|
ff8b167764 | ||
|
|
eee366bebc | ||
|
|
72fa3e14ef | ||
|
|
6324eb041b | ||
|
|
480ec19161 | ||
|
|
39a9e63fe9 | ||
|
|
7ffc38a808 | ||
|
|
97dcf1aca6 | ||
|
|
4dcc613a70 | ||
|
|
b07ab9e848 | ||
|
|
7411365343 | ||
|
|
e6e8745f05 | ||
|
|
e9f737cfeb | ||
|
|
b0cfebadb4 | ||
|
|
eb957dec79 | ||
|
|
eb4927760b | ||
|
|
3719d67596 | ||
|
|
df9ac710d5 | ||
|
|
73109da98d | ||
|
|
c904bc6a5f | ||
|
|
1374ab2bf4 | ||
|
|
429dcdc1d0 | ||
|
|
5de4ae3e61 | ||
|
|
537afa4c7d | ||
|
|
ada8b99f32 | ||
|
|
546da1c354 | ||
|
|
71c0aa1387 | ||
|
|
8414fda99b | ||
|
|
95c1f0fcd0 | ||
|
|
718c3f9347 | ||
|
|
2591fe2de7 |
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
/* @EvanBacon
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: "\U0001F41B Expo Config Plugin Bug Report"
|
name: 🐛 Expo Config Plugin Bug Report
|
||||||
description: Report a reproducible bug with one of the Expo Config Plugins.
|
description: Report a reproducible bug with one of the Expo Config Plugins.
|
||||||
labels: bug
|
labels: bug
|
||||||
body:
|
body:
|
||||||
@@ -30,17 +30,17 @@ body:
|
|||||||
label: Config Plugin
|
label: Config Plugin
|
||||||
options:
|
options:
|
||||||
- '@config-plugins/android-jsc-intl'
|
- '@config-plugins/android-jsc-intl'
|
||||||
|
- '@config-plugins/apple-settings'
|
||||||
- '@config-plugins/detox'
|
- '@config-plugins/detox'
|
||||||
- '@config-plugins/ffmpeg-kit-react-native'
|
- '@config-plugins/ffmpeg-kit-react-native'
|
||||||
- '@config-plugins/ios-stickers'
|
- '@config-plugins/ios-stickers'
|
||||||
- '@config-plugins/react-native-adjust'
|
- '@config-plugins/react-native-adjust'
|
||||||
- '@config-plugins/react-native-ble-plx'
|
|
||||||
- '@config-plugins/react-native-blob-util'
|
- '@config-plugins/react-native-blob-util'
|
||||||
|
- '@config-plugins/react-native-branch'
|
||||||
- '@config-plugins/react-native-callkeep'
|
- '@config-plugins/react-native-callkeep'
|
||||||
- '@config-plugins/react-native-dynamic-app-icon'
|
- '@config-plugins/react-native-dynamic-app-icon'
|
||||||
- '@config-plugins/react-native-google-cast'
|
|
||||||
- '@config-plugins/react-native-pdf'
|
- '@config-plugins/react-native-pdf'
|
||||||
- '@config-plugins/react-native-quick-actions'
|
- '@config-plugins/react-native-siri-shortcut'
|
||||||
- '@config-plugins/react-native-webrtc'
|
- '@config-plugins/react-native-webrtc'
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@@ -1,44 +1,37 @@
|
|||||||
---
|
---
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: "\U0001F914 Question about an Expo Config Plugin"
|
- name: 🤔 Question about an Expo Config Plugin
|
||||||
about: >-
|
about: >-
|
||||||
If you have a question about an Expo Config Plugin, please ask it on the
|
If you have a question about an Expo Config Plugin, please ask it on the
|
||||||
forums, discord, Twitter, or Stack Overflow.
|
forums, discord, Twitter, or Stack Overflow.
|
||||||
url: 'https://forums.expo.io/'
|
url: https://forums.expo.io/
|
||||||
- about: E2E tests and automation for mobile
|
- about: E2E tests and automation for mobile
|
||||||
name: "\U0001F4E6 detox issues"
|
name: 📦 detox issues
|
||||||
url: 'https://github.com/wix/Detox/issues'
|
url: https://github.com/wix/Detox/issues
|
||||||
- about: FFmpeg Kit for React Native
|
- about: FFmpeg Kit for React Native
|
||||||
name: "\U0001F4E6 ffmpeg-kit-react-native issues"
|
name: 📦 ffmpeg-kit-react-native issues
|
||||||
url: 'https://github.com/tanersener/ffmpeg-kit/issues'
|
url: https://github.com/arthenica/ffmpeg-kit/issues
|
||||||
- about: Adjust React Native SDK
|
- about: Adjust React Native SDK
|
||||||
name: "\U0001F4E6 react-native-adjust issues"
|
name: 📦 react-native-adjust issues
|
||||||
url: 'https://github.com/adjust/react_native_sdk/issues'
|
url: https://github.com/adjust/react_native_sdk/issues
|
||||||
- about: React Native Bluetooth Low Energy library
|
|
||||||
name: "\U0001F4E6 react-native-ble-plx issues"
|
|
||||||
url: 'https://github.com/Polidea/react-native-ble-plx/issues'
|
|
||||||
- about: >-
|
- about: >-
|
||||||
A module provides upload, download, and files access API. Supports file
|
A module provides upload, download, and files access API. Supports file
|
||||||
stream read/write for process large files.
|
stream read/write for process large files.
|
||||||
name: "\U0001F4E6 react-native-blob-util issues"
|
name: 📦 react-native-blob-util issues
|
||||||
url: 'https://github.com/RonRadtke/react-native-blob-util/issues'
|
url: https://github.com/RonRadtke/react-native-blob-util/issues
|
||||||
- about: iOS 10 CallKit and Android ConnectionService Framework For React Native
|
- about: iOS 10 CallKit and Android ConnectionService Framework For React Native
|
||||||
name: "\U0001F4E6 react-native-callkeep issues"
|
name: 📦 react-native-callkeep issues
|
||||||
url: 'https://github.com/react-native-webrtc/react-native-callkeep/issues'
|
url: https://github.com/react-native-webrtc/react-native-callkeep/issues
|
||||||
- about: Programmatically change the app icon in React Native.
|
- about: Programmatically change the app icon in React Native.
|
||||||
name: "\U0001F4E6 react-native-dynamic-app-icon issues"
|
name: 📦 react-native-dynamic-app-icon issues
|
||||||
url: 'https://github.com/idearockers/react-native-dynamic-app-icon/issues'
|
url: https://github.com/idearockers/react-native-dynamic-app-icon/issues
|
||||||
- about: React Native wrapper for the Google Cast SDK for iOS and Android
|
- about: A react native PDF view component, support ios and android platform
|
||||||
name: "\U0001F4E6 react-native-google-cast issues"
|
name: 📦 react-native-pdf issues
|
||||||
url: >-
|
url: https://github.com/wonday/react-native-pdf/issues
|
||||||
https://github.com/react-native-google-cast/react-native-google-cast/issues
|
- about: A React Native library that enables you to use iOS 12+ Siri Shortcuts.
|
||||||
- about: 'A react native PDF view component, support ios and android platform'
|
name: 📦 react-native-siri-shortcut issues
|
||||||
name: "\U0001F4E6 react-native-pdf issues"
|
url: https://github.com/Gustash/react-native-siri-shortcut/issues
|
||||||
url: 'https://github.com/wonday/react-native-pdf/issues'
|
|
||||||
- about: A react-native interface for Touch 3D home screen quick actions
|
|
||||||
name: "\U0001F4E6 react-native-quick-actions issues"
|
|
||||||
url: 'https://github.com/jordanbyron/react-native-quick-actions/issues'
|
|
||||||
- about: WebRTC for React Native
|
- about: WebRTC for React Native
|
||||||
name: "\U0001F4E6 react-native-webrtc issues"
|
name: 📦 react-native-webrtc issues
|
||||||
url: 'https://github.com/react-native-webrtc/react-native-webrtc/issues'
|
url: https://github.com/react-native-webrtc/react-native-webrtc/issues
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<!--
|
||||||
|
🚨 We use semantic release (a bot publishes everything automatically)
|
||||||
|
🚨 so please use conventional commit style for the PR title:
|
||||||
|
🚨 https://www.conventionalcommits.org/en/v1.0.0/
|
||||||
|
🚨 Example: feat(detox): add new step
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Why
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Please describe the motivation for this PR, and link to relevant GitHub issues, forums posts, or feature requests.
|
||||||
|
-->
|
||||||
|
|
||||||
|
# How
|
||||||
|
|
||||||
|
<!--
|
||||||
|
How did you build this feature or fix this bug and why?
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Test Plan
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Please describe how you tested this change and how a reviewer could reproduce your test, especially if this PR does not include automated tests! If possible, please also provide terminal output and/or screenshots demonstrating your test/reproduction.
|
||||||
|
-->
|
||||||
@@ -16,5 +16,5 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- run: npm install
|
- run: yarn install --frozen-lockfile --check-files
|
||||||
- run: npx remark --use validate-links . .github
|
- run: npx remark --use validate-links . .github
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
name: PR Title
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- "*"
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- reopened
|
|
||||||
- edited
|
|
||||||
- synchronize
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
main:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: aslafy-z/[email protected]
|
|
||||||
# continue-on-error: true
|
|
||||||
id: title-check
|
|
||||||
with:
|
|
||||||
success-state: PR title is valid
|
|
||||||
failure-state: "PR title does not follow the conventional commit spec: https://www.conventionalcommits.org/en/v1.0.0/"
|
|
||||||
context-name: pr-title
|
|
||||||
preset: conventional-changelog-angular@latest
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
name: Release
|
|
||||||
# https://github.com/bent10/monorepo-starter/blob/main/docs/recipes/release-automation.md
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
name: Releasing
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: "**/node_modules"
|
|
||||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
|
|
||||||
- run: yarn install --frozen-lockfile --check-files
|
|
||||||
- run: yarn lerna run prepare --stream
|
|
||||||
|
|
||||||
# If the dry run fails then it will prevent us from automatically breaking the repo.
|
|
||||||
- name: Semantic release (dry run)
|
|
||||||
run: npx multi-semantic-release --dry-run
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
- name: Semantic release
|
|
||||||
# use `--ignore-packages` to ignore packages on bumping process
|
|
||||||
# npx multi-semantic-release --ignore-packages=packages/a/**,packages/b/**
|
|
||||||
run: npx multi-semantic-release
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node: ["16", "17"]
|
node: ["18"]
|
||||||
name: Build with Node ${{ matrix.node }}
|
name: Build with Node ${{ matrix.node }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
- run: yarn install --frozen-lockfile --check-files
|
- run: yarn install --frozen-lockfile --check-files
|
||||||
- run: yarn lerna run prepare --stream
|
- run: yarn lerna run prepare --stream
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: "*"
|
path: "*"
|
||||||
key: v2-${{ github.sha }}-${{ matrix.node }}
|
key: v2-${{ github.sha }}-${{ matrix.node }}
|
||||||
@@ -32,21 +32,20 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
node: ["16", "17"]
|
node: ["18"]
|
||||||
package: [
|
package: [
|
||||||
# Manually add packages here
|
# Manually add packages here
|
||||||
detox,
|
detox,
|
||||||
ffmpeg-kit-react-native,
|
ffmpeg-kit-react-native,
|
||||||
ios-stickers,
|
ios-stickers,
|
||||||
react-native-ble-plx,
|
|
||||||
react-native-blob-util,
|
react-native-blob-util,
|
||||||
react-native-google-cast,
|
react-native-branch,
|
||||||
|
react-native-siri-shortcut,
|
||||||
react-native-pdf,
|
react-native-pdf,
|
||||||
# react-native-quick-actions,
|
|
||||||
]
|
]
|
||||||
name: Test ${{ matrix.package }} on Node ${{ matrix.node }}
|
name: Test ${{ matrix.package }} on Node ${{ matrix.node }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: "*"
|
path: "*"
|
||||||
key: v2-${{ github.sha }}-${{ matrix.node }}
|
key: v2-${{ github.sha }}-${{ matrix.node }}
|
||||||
@@ -54,8 +53,12 @@ jobs:
|
|||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
|
- name: Lint ${{ matrix.package }}
|
||||||
|
run: yarn lint --max-warnings 0
|
||||||
|
working-directory: packages/${{ matrix.package }}
|
||||||
- name: Test ${{ matrix.package }}
|
- name: Test ${{ matrix.package }}
|
||||||
run: cd packages/${{ matrix.package }} && yarn test
|
run: yarn test
|
||||||
|
working-directory: packages/${{ matrix.package }}
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
EXPO_DEBUG: true
|
EXPO_DEBUG: true
|
||||||
@@ -51,4 +51,16 @@ xcuserdata
|
|||||||
# VSCode
|
# VSCode
|
||||||
.history/
|
.history/
|
||||||
|
|
||||||
# packages/*/build/
|
# Ignore build folders
|
||||||
|
|
||||||
|
packages/*/build/**
|
||||||
|
packages/*/plugin/build/**
|
||||||
|
packages/@*/*/build/**
|
||||||
|
|
||||||
|
|
||||||
|
# App native folders
|
||||||
|
|
||||||
|
apps/*/ios/*
|
||||||
|
apps/*/android/*
|
||||||
|
apps/*/web-build/*
|
||||||
|
apps/*/dist/*
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
// From @byCedric https://github.com/expo/expo-github-action/blob/main/.releaserc.js
|
|
||||||
|
|
||||||
const rules = [
|
|
||||||
{ type: "feat", release: "minor", title: "Features" },
|
|
||||||
{ type: "fix", release: "patch", title: "Bug Fixes" },
|
|
||||||
{ type: "test", release: "patch", title: "Tests" },
|
|
||||||
{ type: "ci", release: "patch", title: "Continuous Integration" },
|
|
||||||
{ type: "refactor", release: "patch", title: "Code Refactoring" },
|
|
||||||
{ type: "chore", release: "patch", title: "Other chores" },
|
|
||||||
{ type: "docs", release: "patch", title: "Documentation changes" },
|
|
||||||
];
|
|
||||||
|
|
||||||
// Simple mapping to order the commit groups
|
|
||||||
const sortMap = Object.fromEntries(
|
|
||||||
rules.map((rule, index) => [rule.title, index])
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
branches: ["main"],
|
|
||||||
tagFormat: "${version}",
|
|
||||||
repositoryUrl: "https://github.com/expo/config-plugins.git",
|
|
||||||
plugins: [
|
|
||||||
[
|
|
||||||
"@semantic-release/commit-analyzer",
|
|
||||||
{
|
|
||||||
preset: "conventionalcommits",
|
|
||||||
releaseRules: [
|
|
||||||
{ breaking: true, release: "major" },
|
|
||||||
{ revert: true, release: "patch" },
|
|
||||||
].concat(
|
|
||||||
rules.map(({ type, release, breaking }) => ({
|
|
||||||
type,
|
|
||||||
release,
|
|
||||||
breaking,
|
|
||||||
}))
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@semantic-release/release-notes-generator",
|
|
||||||
{
|
|
||||||
preset: "conventionalcommits",
|
|
||||||
presetConfig: {
|
|
||||||
types: rules.map(({ type, title }) => ({ type, section: title })),
|
|
||||||
},
|
|
||||||
writerOpts: {
|
|
||||||
commitGroupsSort: (a, z) => sortMap[a.title] - sortMap[z.title],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"@semantic-release/changelog",
|
|
||||||
[
|
|
||||||
"@semantic-release/git",
|
|
||||||
{
|
|
||||||
message: "chore: ${nextRelease.version}\n\n${nextRelease.notes}",
|
|
||||||
assets: ["package.json", "CHANGELOG.md", "build/*"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"@semantic-release/github",
|
|
||||||
"@semantic-release/npm",
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@@ -5,10 +5,22 @@
|
|||||||
To submit a pull request:
|
To submit a pull request:
|
||||||
|
|
||||||
1. Fork the [repository](https://github.com/expo/config-plugins) and create a feature branch. (Existing contributors can create feature branches without forking. Prefix the branch name with `@your-github-username/`.)
|
1. Fork the [repository](https://github.com/expo/config-plugins) and create a feature branch. (Existing contributors can create feature branches without forking. Prefix the branch name with `@your-github-username/`.)
|
||||||
2. Use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) including in the PR tile.
|
2. Run `yarn` in the root directory to generate the build files.
|
||||||
3. Fill out the entire PR template. Ensure your code is tested locally and has continuous tests in CI.
|
3. Use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) including in the PR title.
|
||||||
4. Make sure all tests pass on GitHub Actions.
|
4. Fill out the entire PR template. Ensure your code is tested locally and has continuous tests in CI.
|
||||||
5. Wait for a review and adjust the code if necessary.
|
5. Make sure all tests pass on GitHub Actions.
|
||||||
|
6. Wait for a review and adjust the code if necessary.
|
||||||
|
|
||||||
|
## Creating a plugin
|
||||||
|
|
||||||
|
- Plugins can be generated by running `yarn gen`.
|
||||||
|
- Add plugins to the example in [`apps/app`](/apps/app/package.json) to test them.
|
||||||
|
- The example app should always stay in a state of regeneration.
|
||||||
|
|
||||||
|
Be sure to run the following scripts in the **root directory** to update automation tools:
|
||||||
|
|
||||||
|
- Update dependabot: `yarn update-dependabot-config`
|
||||||
|
- Update the issue template: `yarn update-issue-template`
|
||||||
|
|
||||||
## Publishing a release
|
## Publishing a release
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,69 @@
|
|||||||
# Expo Config Plugins
|
# Expo Config Plugins
|
||||||
|
|
||||||
A collection of custom WIP config plugins for Expo dev clients. Use at your own discretion.
|
- A collection of [Expo config plugins](https://docs.expo.dev/guides/config-plugins/) for configuring the `npx expo prebuild` command.
|
||||||
|
- This repo is to Expo config plugins as [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) is to TypeScript.
|
||||||
|
- We prefer packages ship their own Expo config plugin (to ensure versioning is aligned), but if they haven't adopted the system yet, the community can add a package here.
|
||||||
|
- All packages here are community maintained. Feel free to improve docs, packages, tests, etc.
|
||||||
|
- We maintain a 1-1 mapping of **native packages** ⇔ `@config-plugins/*`. This means there should be no general utility packages here -- those are better suited for a different repo / NPM namespace.
|
||||||
|
|
||||||
|
## First-party plugins
|
||||||
|
|
||||||
## Creating a plugin
|
Here is a list of known packages that have a built-in Config Plugin.
|
||||||
|
|
||||||
- Plugins can be generated by running `yarn gen`.
|
> Not all packages need a config plugin, packages that don't appear here might still work with managed EAS.
|
||||||
- Add plugins to the example in [`apps/app`](/apps/app/package.json) to test them.
|
|
||||||
- The example app should always stay in a state of regeneration.
|
- [React Native Firebase](https://rnfirebase.io/) (`@react-native-firebase/perf`, `@react-native-firebase/app`, `@react-native-firebase/crashlytics`)
|
||||||
|
- [react-native-google-cast](https://github.com/react-native-google-cast/react-native-google-cast)
|
||||||
|
- [react-native-nfc-manager](https://github.com/revtel/react-native-nfc-manager)
|
||||||
|
- [react-native-health](https://github.com/agencyenterprise/react-native-health)
|
||||||
|
- [@react-native-mapbox-gl/maps](https://github.com/rnmapbox/maps)
|
||||||
|
- [@logrocket/react-native](https://www.npmjs.com/package/@logrocket/react-native)
|
||||||
|
- [sentry-expo](https://www.npmjs.com/package/sentry-expo)
|
||||||
|
- [@leanplum/react-native-sdk](https://github.com/Leanplum/Leanplum-ReactNative-SDK#readme)
|
||||||
|
- [react-native-fbsdk-next](https://www.npmjs.com/package/react-native-fbsdk-next)
|
||||||
|
- [@stripe/stripe-react-native](https://www.npmjs.com/package/@stripe/stripe-react-native)
|
||||||
|
- [@react-native-voice/voice](https://www.npmjs.com/package/@react-native-voice/voice)
|
||||||
|
- [react-native-imglysdk](https://www.npmjs.com/package/react-native-imglysdk)
|
||||||
|
- [@viro-community/react-viro](https://github.com/virocommunity/viro) -- [Guide](https://viro-community.readme.io/docs/integrating-with-expo)
|
||||||
|
- [react-native-msal](https://www.npmjs.com/package/react-native-msal)
|
||||||
|
- [react-native-spotlight-search](https://www.npmjs.com/package/react-native-spotlight-search)
|
||||||
|
- [newrelic-react-native-agent](https://www.npmjs.com/package/newrelic-react-native-agent)
|
||||||
|
- [react-native-videoeditorsdk](https://www.npmjs.com/package/react-native-videoeditorsdk)
|
||||||
|
- [notifee](https://notifee.app/)
|
||||||
|
- [App Clips](https://github.com/bndkt/react-native-app-clip/)
|
||||||
|
- [iOS Safari Extensions](https://github.com/andrew-levy/react-native-safari-extension/)
|
||||||
|
- [react-native-ble-plx](https://github.com/dotintent/react-native-ble-plx)
|
||||||
|
|
||||||
|
### Complementary
|
||||||
|
|
||||||
|
More out-of-tree plugins which can be used to configure more packages.
|
||||||
|
|
||||||
|
- [onesignal-expo-plugin](https://github.com/OneSignal/onesignal-expo-plugin) (for use with `react-native-onesignal`)
|
||||||
|
- Configures **iOS Notification Service Extensions** for rich push notification and custom notification actions.
|
||||||
|
- [@lyrahealth-inc/react-native-orientation-plugin](https://www.npmjs.com/package/@lyrahealth-inc/react-native-orientation-plugin) (for use with `react-native-orientation-plugin`)
|
||||||
|
- [airship-expo-plugin](https://www.npmjs.com/package/airship-expo-plugin) (for use with `urbanairship-react-native`)
|
||||||
|
- [config-plugin-react-native-intercom](https://www.npmjs.com/package/config-plugin-react-native-intercom) (for use with `intercom-react-native`)
|
||||||
|
- [@allboatsrise/expo-marketingcloudsdk](https://www.npmjs.com/package/@allboatsrise/expo-marketingcloudsdk) (for use with `react-native-marketingcloudsdk`)
|
||||||
|
- [@ouvio/react-native-background-location-plugin](https://www.npmjs.com/package/@ouvio/react-native-background-location-plugin) (for use with `react-native-background-location-plugin`)
|
||||||
|
- [expo-community-flipper](https://www.npmjs.com/package/expo-community-flipper) (for use with Flipper)
|
||||||
|
- [expo-appcenter](https://www.npmjs.com/package/expo-appcenter) (for use with `appcenter`)
|
||||||
|
- [expo-react-native-freshchat](https://www.npmjs.com/package/expo-react-native-freshchat) (for use with `react-native-freshchat-sdk`)
|
||||||
|
- [react-native-keyevent-expo-config-plugin](https://github.com/chronsyn/react-native-keyevent-expo-config-plugin) (for use with `react-native-keyevent`)
|
||||||
|
- [watermelondb-expo-plugin](https://github.com/morrowdigital/watermelondb-expo-plugin) (for use with `@nozbe/watermelondb`)
|
||||||
|
|
||||||
|
### No Plugin Required
|
||||||
|
|
||||||
|
Just install and rebuild! If a package doesn't require any futher setup then it most likely doesn't need an Expo config plugin. Most packages work without a config plugin (including packages not listed below):
|
||||||
|
|
||||||
|
- [react-native-share](https://github.com/react-native-share/react-native-share)
|
||||||
|
- [@react-native-menu/menu](https://github.com/react-native-menu/menu)
|
||||||
|
- [react-native-blurhash](https://github.com/mrousavy/react-native-blurhash)
|
||||||
|
- [react-native-app-shortcuts](https://github.com/lokyoung/react-native-app-shortcuts)
|
||||||
|
- [react-native-multiple-image-picker](https://github.com/baronha/react-native-multiple-image-picker)
|
||||||
|
- [`@shopify/flash-list`](https://github.com/Shopify/flash-list)
|
||||||
|
|
||||||
|
> Feel free to [open a PR](https://github.com/expo/config-plugins/edit/main/README.md) with missing packages.
|
||||||
|
|
||||||
|
## Contributing!
|
||||||
|
|
||||||
|
See the [contributing guide](/CONTRIBUTING.md).
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
|
|
||||||
"40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
|
|
||||||
}
|
|
||||||
@@ -1,80 +1,2 @@
|
|||||||
node_modules/**/*
|
|
||||||
.expo/*
|
|
||||||
npm-debug.*
|
|
||||||
*.jks
|
|
||||||
*.p8
|
|
||||||
*.p12
|
|
||||||
*.key
|
|
||||||
*.mobileprovision
|
|
||||||
*.orig.*
|
|
||||||
web-build/
|
|
||||||
|
|
||||||
# macOS
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
|
|
||||||
/artifacts
|
|
||||||
|
|
||||||
/scripts/start.command
|
/scripts/start.command
|
||||||
/ios
|
/artifacts
|
||||||
/android
|
|
||||||
# @generated expo-cli sync-e7dcf75f4e856f7b6f3239b3f3a7dd614ee755a8
|
|
||||||
# The following patterns were generated by expo-cli
|
|
||||||
|
|
||||||
# OSX
|
|
||||||
#
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Xcode
|
|
||||||
#
|
|
||||||
build/
|
|
||||||
*.pbxuser
|
|
||||||
!default.pbxuser
|
|
||||||
*.mode1v3
|
|
||||||
!default.mode1v3
|
|
||||||
*.mode2v3
|
|
||||||
!default.mode2v3
|
|
||||||
*.perspectivev3
|
|
||||||
!default.perspectivev3
|
|
||||||
xcuserdata
|
|
||||||
*.xccheckout
|
|
||||||
*.moved-aside
|
|
||||||
DerivedData
|
|
||||||
*.hmap
|
|
||||||
*.ipa
|
|
||||||
*.xcuserstate
|
|
||||||
project.xcworkspace
|
|
||||||
|
|
||||||
# Android/IntelliJ
|
|
||||||
#
|
|
||||||
build/
|
|
||||||
.idea
|
|
||||||
.gradle
|
|
||||||
local.properties
|
|
||||||
*.iml
|
|
||||||
*.hprof
|
|
||||||
|
|
||||||
# node.js
|
|
||||||
#
|
|
||||||
node_modules/
|
|
||||||
npm-debug.log
|
|
||||||
yarn-error.log
|
|
||||||
|
|
||||||
# BUCK
|
|
||||||
buck-out/
|
|
||||||
\.buckd/
|
|
||||||
*.keystore
|
|
||||||
!debug.keystore
|
|
||||||
|
|
||||||
# Bundle artifacts
|
|
||||||
*.jsbundle
|
|
||||||
|
|
||||||
# CocoaPods
|
|
||||||
/ios/Pods/
|
|
||||||
|
|
||||||
# Expo
|
|
||||||
.expo/
|
|
||||||
web-build/
|
|
||||||
dist/
|
|
||||||
|
|
||||||
# @end expo-cli
|
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
// export { default } from './src/react-native-quick-actions/App';
|
export { default } from "./src/detox/App";
|
||||||
// export { default } from './src/react-native-pdf/App';
|
// export { default } from "./src/android-jsc-intl/App";
|
||||||
// export { default } from './src/react-native-dynamic-app-icon/App';
|
// export { default } from "./src/react-native-adjust/App";
|
||||||
// export { default } from './src/react-native-google-cast/App';
|
|
||||||
// export { default } from './src/detox/App';
|
|
||||||
// export { default } from './src/react-native-ble-plx/App';
|
|
||||||
export { default } from './src/react-native-webrtc/App';
|
|
||||||
// export { default } from './src/android-jsc-intl/App';
|
|
||||||
// export { default } from './src/ffmpeg-kit-react-native/App';
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
### @expo/app [1.0.1](https://github.com/expo/config-plugins/compare/@expo/[email protected]...@expo/[email protected]) (2022-03-15)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **ci:** use correct internal versions ([ab8076a](https://github.com/expo/config-plugins/commit/ab8076adf51e9ba0439eba60b153d729a0996b8d))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
* **@config-plugins/android-jsc-intl:** upgraded to 1.0.1
|
|
||||||
* **@config-plugins/detox:** upgraded to 1.0.1
|
|
||||||
* **@config-plugins/react-native-adjust:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-ble-plx:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-blob-util:** upgraded to 1.0.1
|
|
||||||
* **@config-plugins/react-native-branch:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-callkeep:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-dynamic-app-icon:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-google-cast:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-pdf:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-quick-actions:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-webrtc:** upgraded to 1.0.0
|
|
||||||
|
|
||||||
## @expo/app 1.0.0 (2022-03-15)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* create react-native-branch plugin ([0b06baa](https://github.com/expo/config-plugins/commit/0b06baa2b486c5e02d433a4ac785960934f403b9))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* respect old config from expo-branch ([d0e0186](https://github.com/expo/config-plugins/commit/d0e018601c09c0e92191a4eb2998ab0e6fa1c6ec))
|
|
||||||
|
|
||||||
|
|
||||||
### Other chores
|
|
||||||
|
|
||||||
* added start-metro script ([4a7d707](https://github.com/expo/config-plugins/commit/4a7d707b200a3e499d9d71caf49ad4fc1d0a89e0))
|
|
||||||
* update script ([dcf61a9](https://github.com/expo/config-plugins/commit/dcf61a9b9542851095954d84c9054c97c5400dc9))
|
|
||||||
* upgrade to latest react-native-branch ([df98474](https://github.com/expo/config-plugins/commit/df98474d79ed139b42ddd698d13100160c656c26))
|
|
||||||
|
|
||||||
|
|
||||||
### Documentation changes
|
|
||||||
|
|
||||||
* add android-jsc-intl example ([d96c0b2](https://github.com/expo/config-plugins/commit/d96c0b2888da3808d7c4e2dd7993129711ba717d))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
* **@config-plugins/android-jsc-intl:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/detox:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/ffmpeg-kit-react-native:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/ios-stickers:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-adjust:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-ble-plx:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-blob-util:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-branch:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-callkeep:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-dynamic-app-icon:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-google-cast:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-pdf:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-quick-actions:** upgraded to 1.0.0
|
|
||||||
* **@config-plugins/react-native-webrtc:** upgraded to 1.0.0
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"expo": {
|
"expo": {
|
||||||
"name": "app",
|
"name": "detoxapp",
|
||||||
"slug": "app",
|
"slug": "app",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"orientation": "portrait",
|
"orientation": "portrait",
|
||||||
"icon": "./assets/icons/winter.png",
|
"icon": "https://github.com/expo.png",
|
||||||
"splash": {
|
"splash": {
|
||||||
"image": "./assets/splash.png",
|
"image": "./assets/splash.png",
|
||||||
"resizeMode": "contain",
|
"resizeMode": "contain",
|
||||||
@@ -16,86 +16,24 @@
|
|||||||
"assetBundlePatterns": ["**/*"],
|
"assetBundlePatterns": ["**/*"],
|
||||||
"ios": {
|
"ios": {
|
||||||
"supportsTablet": true,
|
"supportsTablet": true,
|
||||||
"bundleIdentifier": "dev.bacon.app",
|
"bundleIdentifier": "dev.bacon.app"
|
||||||
"config": {
|
|
||||||
"branch": {
|
|
||||||
"apiKey": "key_live_f9f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"android": {
|
"android": {
|
||||||
"adaptiveIcon": {
|
"adaptiveIcon": {
|
||||||
"foregroundImage": "./assets/adaptive-icon.png",
|
"foregroundImage": "./assets/adaptive-icon.png",
|
||||||
"backgroundColor": "#FFFFFF"
|
"backgroundColor": "#FFFFFF"
|
||||||
},
|
},
|
||||||
"config": {
|
|
||||||
"branch": {
|
|
||||||
"apiKey": "key_live_f9f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"package": "com.bacon.app"
|
"package": "com.bacon.app"
|
||||||
},
|
},
|
||||||
"web": {
|
"web": {
|
||||||
"favicon": "./assets/favicon.png"
|
"favicon": "./assets/favicon.png"
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
[
|
|
||||||
"@config-plugins/react-native-dynamic-app-icon",
|
|
||||||
[
|
|
||||||
"./assets/icons/spring.png",
|
|
||||||
"./assets/icons/summer.png",
|
|
||||||
"./assets/icons/autumn.png",
|
|
||||||
"./assets/icons/fall.png",
|
|
||||||
"./assets/icons/solstice.png"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@config-plugins/react-native-quick-actions",
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"title": "Take Photo",
|
|
||||||
"type": "photo",
|
|
||||||
"iconType": "UIApplicationShortcutIconTypeCapturePhoto"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@config-plugins/ffmpeg-kit-react-native",
|
|
||||||
{
|
|
||||||
"package": "min"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@config-plugins/detox",
|
"@config-plugins/detox",
|
||||||
"@config-plugins/react-native-adjust",
|
"@config-plugins/react-native-adjust",
|
||||||
"@config-plugins/react-native-branch",
|
|
||||||
"@config-plugins/react-native-google-cast",
|
|
||||||
"@config-plugins/react-native-ble-plx",
|
|
||||||
"@config-plugins/react-native-webrtc",
|
|
||||||
"@config-plugins/react-native-callkeep",
|
"@config-plugins/react-native-callkeep",
|
||||||
"@config-plugins/react-native-blob-util",
|
|
||||||
"@config-plugins/react-native-pdf",
|
|
||||||
"@config-plugins/android-jsc-intl",
|
"@config-plugins/android-jsc-intl",
|
||||||
[
|
"expo-localization"
|
||||||
"@config-plugins/ios-stickers",
|
|
||||||
{
|
|
||||||
"name": "Stickers",
|
|
||||||
"icon": "./assets/imessage-icon.png",
|
|
||||||
"columns": 4,
|
|
||||||
"stickers": [
|
|
||||||
"./assets/stickers/annoyed.png",
|
|
||||||
"./assets/stickers/cuddle.png",
|
|
||||||
"./assets/stickers/crazy.png",
|
|
||||||
"./assets/stickers/cant.png",
|
|
||||||
"./assets/stickers/donno.png",
|
|
||||||
"./assets/stickers/cozzy.png",
|
|
||||||
"./assets/stickers/dork.png",
|
|
||||||
"./assets/stickers/focus.png",
|
|
||||||
"./assets/stickers/avocool.png",
|
|
||||||
"./assets/stickers/coder-girl.png",
|
|
||||||
"./assets/stickers/teapot.png"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
module.exports = function(api) {
|
|
||||||
api.cache(true);
|
|
||||||
return {
|
|
||||||
presets: ['babel-preset-expo'],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,13 +1,21 @@
|
|||||||
const iosName = "app";
|
const iosName = "detoxapp";
|
||||||
const emulator = "Pixel_3a_API_30";
|
const simulator = "iPhone 16";
|
||||||
const simulator = "iPhone 13 Pro";
|
|
||||||
const derivedDataPath = "ios/build";
|
const derivedDataPath = "ios/build";
|
||||||
const sdk = "iphonesimulator";
|
const sdk = "iphonesimulator";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
testRunner: "jest",
|
testRunner: {
|
||||||
runnerConfig: require.resolve("./e2e/jest.config.js"),
|
$0: "jest",
|
||||||
specs: "e2e",
|
args: {
|
||||||
|
config: require.resolve("./e2e/jest.config.js"),
|
||||||
|
_: ["e2e"],
|
||||||
|
},
|
||||||
|
jest: {
|
||||||
|
setupTimeout: 300000,
|
||||||
|
reportSpecs: true,
|
||||||
|
reportWorkerAssign: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
behavior: {
|
behavior: {
|
||||||
init: {
|
init: {
|
||||||
exposeGlobals: false,
|
exposeGlobals: false,
|
||||||
@@ -47,7 +55,7 @@ module.exports = {
|
|||||||
emulator: {
|
emulator: {
|
||||||
type: "android.emulator",
|
type: "android.emulator",
|
||||||
device: {
|
device: {
|
||||||
avdName: emulator,
|
avdName: "Pixel_6_Pro_API_33",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
const {
|
|
||||||
DetoxCircusEnvironment,
|
|
||||||
SpecReporter,
|
|
||||||
WorkerAssignReporter,
|
|
||||||
} = require("detox/runners/jest-circus");
|
|
||||||
|
|
||||||
class CustomDetoxEnvironment extends DetoxCircusEnvironment {
|
|
||||||
constructor(config, context) {
|
|
||||||
super(config, context);
|
|
||||||
|
|
||||||
// Can be safely removed, if you are content with the default value (=300000ms)
|
|
||||||
this.initTimeout = 300000;
|
|
||||||
|
|
||||||
// This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level.
|
|
||||||
// This is strictly optional.
|
|
||||||
this.registerListeners({
|
|
||||||
SpecReporter,
|
|
||||||
WorkerAssignReporter,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = CustomDetoxEnvironment;
|
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
testEnvironment: require.resolve("./environment.js"),
|
|
||||||
testRunner: require.resolve("jest-circus/runner"),
|
testRunner: require.resolve("jest-circus/runner"),
|
||||||
testTimeout: 120000,
|
testTimeout: 120000,
|
||||||
testRegex: "/__tests__/.*(e2e)\\.[jt]sx?$",
|
rootDir: "..",
|
||||||
|
testMatch: ["<rootDir>/**/__tests__/*"],
|
||||||
transform: {
|
transform: {
|
||||||
"^.+\\.[jt]sx?$": "ts-jest",
|
"^.+\\.[jt]sx?$": "ts-jest",
|
||||||
},
|
},
|
||||||
reporters: [require.resolve("detox/runners/jest/streamlineReporter")],
|
reporters: [require.resolve("detox/runners/jest/reporter")],
|
||||||
|
globalSetup: "detox/runners/jest/globalSetup",
|
||||||
|
globalTeardown: "detox/runners/jest/globalTeardown",
|
||||||
|
testEnvironment: "detox/runners/jest/testEnvironment",
|
||||||
verbose: true,
|
verbose: true,
|
||||||
};
|
};
|
||||||
|
Before Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 86 KiB |
@@ -1,6 +0,0 @@
|
|||||||
// Learn more https://docs.expo.io/guides/customizing-metro
|
|
||||||
const { getDefaultConfig } = require("@expo/metro-config");
|
|
||||||
|
|
||||||
const config = getDefaultConfig(__dirname);
|
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
@@ -21,59 +21,32 @@
|
|||||||
"android": "expo run:android"
|
"android": "expo run:android"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@config-plugins/android-jsc-intl": "1.0.1",
|
"@config-plugins/android-jsc-intl": "*",
|
||||||
"@config-plugins/detox": "1.0.1",
|
"@config-plugins/detox": "*",
|
||||||
"@config-plugins/ffmpeg-kit-react-native": "1.0.0",
|
"@config-plugins/react-native-adjust": "*",
|
||||||
"@config-plugins/ios-stickers": "1.0.0",
|
"@config-plugins/react-native-callkeep": "*",
|
||||||
"@config-plugins/react-native-adjust": "1.0.0",
|
"detox": "^20.37.0",
|
||||||
"@config-plugins/react-native-ble-plx": "1.0.0",
|
"expo": "~53",
|
||||||
"@config-plugins/react-native-blob-util": "1.0.1",
|
"expo-localization": "~16.1.5",
|
||||||
"@config-plugins/react-native-branch": "1.0.0",
|
"expo-splash-screen": "~0.30.7",
|
||||||
"@config-plugins/react-native-callkeep": "1.0.0",
|
|
||||||
"@config-plugins/react-native-dynamic-app-icon": "1.0.0",
|
|
||||||
"@config-plugins/react-native-google-cast": "1.0.0",
|
|
||||||
"@config-plugins/react-native-pdf": "1.0.0",
|
|
||||||
"@config-plugins/react-native-quick-actions": "1.0.0",
|
|
||||||
"@config-plugins/react-native-webrtc": "1.0.0",
|
|
||||||
"expo": "^44.0.0",
|
|
||||||
"expo-localization": "~12.0.0",
|
|
||||||
"expo-splash-screen": "~0.14.0",
|
|
||||||
"expo-status-bar": "~1.2.0",
|
|
||||||
"expo-updates": "~0.11.2",
|
|
||||||
"fbjs": "^0.8.18",
|
"fbjs": "^0.8.18",
|
||||||
"ffmpeg-kit-react-native": "^4.5.0",
|
|
||||||
"i18n-js": "^3.8.0",
|
"i18n-js": "^3.8.0",
|
||||||
"luxon": "^1.27.0",
|
"luxon": "^1.27.0",
|
||||||
"react": "17.0.1",
|
"react": "19.0.0",
|
||||||
"react-dom": "17.0.1",
|
"react-native": "0.79.2",
|
||||||
"react-native": "0.64.3",
|
"react-native-adjust": "^5.1.0",
|
||||||
"react-native-adjust": "^4.29.5",
|
"react-native-callkeep": "^4.3.16",
|
||||||
"react-native-blob-util": "^0.13.17",
|
"react-native-safe-area-context": "5.3.0"
|
||||||
"react-native-callkeep": "^4.2.0",
|
|
||||||
"react-native-branch": "^5.3.0",
|
|
||||||
"react-native-dynamic-app-icon": "^1.1.0",
|
|
||||||
"react-native-google-cast": "^4.1.2",
|
|
||||||
"react-native-pdf": "^6.4.0",
|
|
||||||
"react-native-quick-actions": "^0.3.13",
|
|
||||||
"react-native-safe-area-context": "3.3.2",
|
|
||||||
"react-native-web": "0.17.1",
|
|
||||||
"react-native-webrtc": "^1.89.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.9",
|
|
||||||
"@babel/plugin-syntax-jsx": "^7.16.0",
|
"@babel/plugin-syntax-jsx": "^7.16.0",
|
||||||
"@expo/metro-config": "~0.3.7",
|
"@types/jest": "^29.4.0",
|
||||||
"@expo/xcpretty": "^4.1.0",
|
|
||||||
"@types/jest": "^26.0.19",
|
|
||||||
"@types/luxon": "^1.27.1",
|
"@types/luxon": "^1.27.1",
|
||||||
"@types/react": "~17.0.21",
|
"babel-jest": "^29.5.0",
|
||||||
"@types/react-native": "~0.64.12",
|
"jest": "~29.7.0",
|
||||||
"babel-jest": "~25.2.6",
|
"jest-circus": "^29.5.0",
|
||||||
"detox": "^19.1.0",
|
"ts-jest": "^29.0.5",
|
||||||
"jest": "^26.6.3",
|
"typescript": "~5.8.3"
|
||||||
"jest-circus": "^26.5.2",
|
|
||||||
"ts-jest": "^26.4.4",
|
|
||||||
"typescript": "~4.3.5"
|
|
||||||
},
|
},
|
||||||
"private": true
|
"private": true
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ set -eu
|
|||||||
|
|
||||||
iosName=$1
|
iosName=$1
|
||||||
# Debug or Release
|
# Debug or Release
|
||||||
configuration=$2
|
configuration=${3:-"Debug"}
|
||||||
# YES or NO
|
# YES or NO
|
||||||
UseModernBuildSystem=${3:-"NO"}
|
UseModernBuildSystem=${3:-"NO"}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ else
|
|||||||
commandFile=$(dirname "$0")/start.command
|
commandFile=$(dirname "$0")/start.command
|
||||||
cat > ${commandFile} << EOF
|
cat > ${commandFile} << EOF
|
||||||
cd "\$(dirname "\$0")/.."
|
cd "\$(dirname "\$0")/.."
|
||||||
# Run 'react-native start --help' to get more parameters
|
# Run 'npx expo start --help' to get more parameters
|
||||||
yarn start --port ${port}
|
yarn start --port ${port}
|
||||||
EOF
|
EOF
|
||||||
# execute the file in a new command line window
|
# execute the file in a new command line window
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import { Session } from 'ffmpeg-kit-react-native';
|
|
||||||
import React from 'react';
|
|
||||||
import { ActivityIndicator, SafeAreaView, ScrollView, Text, View } from 'react-native';
|
|
||||||
|
|
||||||
import { useMediaInfo, useResolvedValue } from './useMediaInfo';
|
|
||||||
|
|
||||||
export default function App() {
|
|
||||||
const session = useMediaInfo('http://techslides.com/demos/sample-videos/small.mp4');
|
|
||||||
|
|
||||||
if (!session) {
|
|
||||||
return <View style={{
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
}}><ActivityIndicator /><Text>Loading...</Text></View>
|
|
||||||
}
|
|
||||||
|
|
||||||
return <SessionInfo session={session} />
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function SessionInfo(props: { session: Session }) {
|
|
||||||
const { session } = props;
|
|
||||||
const duration = useResolvedValue(session.getDuration.bind(session));
|
|
||||||
const output = useResolvedValue(session.getOutput.bind(session));
|
|
||||||
return (
|
|
||||||
<SafeAreaView
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ScrollView>
|
|
||||||
<Text>Duration: {duration}</Text>
|
|
||||||
<Text>Output: {output}</Text>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@ export default function App() {
|
|||||||
"APP_TOKEN",
|
"APP_TOKEN",
|
||||||
AdjustConfig.EnvironmentSandbox
|
AdjustConfig.EnvironmentSandbox
|
||||||
);
|
);
|
||||||
Adjust.create(adjustConfig);
|
Adjust.enable();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Text, View } from 'react-native';
|
|
||||||
|
|
||||||
import useBluetoothDevices, { useManager, useManagerState } from './useBluetoothDevices';
|
|
||||||
|
|
||||||
export default function App() {
|
|
||||||
const bleManager = useManager();
|
|
||||||
const state = useManagerState(bleManager);
|
|
||||||
|
|
||||||
console.log('Info:', state);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'blue'}}>
|
|
||||||
<Text style={{fontSize: 18, color: 'white'}}>State: {state}</Text>
|
|
||||||
{state === 'PoweredOn' && <DeviceScanner bleManager={bleManager} />}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function DeviceScanner({ bleManager }) {
|
|
||||||
const [devices] = useBluetoothDevices(bleManager);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
console.log(devices);
|
|
||||||
}, [devices]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
{devices.filter(({name}) => name).map((device, index) => (<Text key={`-${index}`} style={{fontSize: 14, color: 'white'}}>{device.name}</Text>))}
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
|
||||||
import { BleManager, State, Device } from "react-native-ble-plx";
|
|
||||||
import { uniqBy } from "lodash";
|
|
||||||
|
|
||||||
export function useManager() {
|
|
||||||
return useMemo(() => new BleManager(), []);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useManagerState(bleManager: BleManager): State | null {
|
|
||||||
const [state, setState] = useState<State | null>(null);
|
|
||||||
const isMounted = useMounted();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!bleManager) return;
|
|
||||||
|
|
||||||
bleManager.onStateChange((state) => {
|
|
||||||
if (isMounted.current) {
|
|
||||||
setState(state);
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
}, [bleManager]);
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
function useMounted() {
|
|
||||||
const isMounted = useRef(true);
|
|
||||||
useEffect(() => {
|
|
||||||
isMounted.current = true;
|
|
||||||
return () => {
|
|
||||||
isMounted.current = false;
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
return isMounted;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useBluetoothDevices(
|
|
||||||
bleManager: BleManager
|
|
||||||
): [Device[], null | string] {
|
|
||||||
const isMoutned = useMounted();
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
const [devices, setDevices] = useState<Device[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
bleManager.startDeviceScan(
|
|
||||||
[],
|
|
||||||
{ allowDuplicates: false },
|
|
||||||
(e, scannedDevice) => {
|
|
||||||
if (!isMoutned.current) return;
|
|
||||||
if (e) {
|
|
||||||
setError(e.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scannedDevice) return;
|
|
||||||
|
|
||||||
setDevices((oldDevices) =>
|
|
||||||
uniqBy([...oldDevices, scannedDevice], "id")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
bleManager.stopDeviceScan();
|
|
||||||
};
|
|
||||||
}, [bleManager]);
|
|
||||||
|
|
||||||
return [devices, error];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useBluetoothDevices;
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
import Entypo from '@expo/vector-icons/Entypo';
|
|
||||||
import React from 'react';
|
|
||||||
import { Image, SafeAreaView, Text, View } from 'react-native';
|
|
||||||
import AppIcon from 'react-native-dynamic-app-icon';
|
|
||||||
import TouchableBounce from 'react-native/Libraries/Components/Touchable/TouchableBounce';
|
|
||||||
|
|
||||||
function useIconName() {
|
|
||||||
const [icon, _setIcon] = React.useState(null);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
let isMounted = true;
|
|
||||||
AppIcon.getIconName((result) => {
|
|
||||||
if (isMounted) _setIcon(result.iconName);
|
|
||||||
});
|
|
||||||
return () => (isMounted = false);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setIcon = React.useCallback(
|
|
||||||
(icon) => {
|
|
||||||
AppIcon.setAppIcon(icon);
|
|
||||||
_setIcon(icon || null);
|
|
||||||
},
|
|
||||||
[_setIcon]
|
|
||||||
);
|
|
||||||
return [icon === "default" ? null : icon, setIcon];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const icons = [
|
|
||||||
{ name: "Auto", source: require("../../assets/icons/winter.png"), iconId: null },
|
|
||||||
{ name: "Spring", source: require("../../assets/icons/spring.png"), iconId: '0' },
|
|
||||||
{ name: "Summer", source: require("../../assets/icons/summer.png"), iconId: '1' },
|
|
||||||
{ name: "Autumn", source: require("../../assets/icons/autumn.png"), iconId: '2' },
|
|
||||||
{ name: "Fall", source: require("../../assets/icons/fall.png"), iconId: '3' },
|
|
||||||
{ name: "Solstice", source: require("../../assets/icons/solstice.png"), iconId: '4' },
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function App() {
|
|
||||||
const [_icon, setIcon] = useIconName();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SafeAreaView
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View style={{ width: "100%" }}>
|
|
||||||
{icons.map((icon, index) => {
|
|
||||||
return (
|
|
||||||
<Item
|
|
||||||
onPress={() => {
|
|
||||||
setIcon(icon.iconId);
|
|
||||||
}}
|
|
||||||
isSelected={icon.iconId === _icon}
|
|
||||||
name={icon.name}
|
|
||||||
source={icon.source}
|
|
||||||
key={String(index)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</View>
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Item({ ...props }) {
|
|
||||||
return (
|
|
||||||
<TouchableBounce
|
|
||||||
onPress={props.onPress}
|
|
||||||
style={{ marginVertical: 8, marginHorizontal: 24 }}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
|
|
||||||
style={{
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "stretch",
|
|
||||||
shadowColor: "#000",
|
|
||||||
shadowOffset: {
|
|
||||||
width: 0,
|
|
||||||
height: 4,
|
|
||||||
},
|
|
||||||
shadowOpacity: props.isSelected ? 0.35 : 0.2,
|
|
||||||
shadowRadius: 8.46,
|
|
||||||
|
|
||||||
backgroundColor: props.isSelected ? "#000" : "#F1F1F1",
|
|
||||||
elevation: 9,
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
paddingVertical: 12,
|
|
||||||
borderRadius: 20,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flexDirection: "row",
|
|
||||||
flex: 1,
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flexDirection: "row",
|
|
||||||
flex: 1,
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
source={props.source}
|
|
||||||
style={{
|
|
||||||
width: 64,
|
|
||||||
aspectRatio: 1,
|
|
||||||
resizeMode: "cover",
|
|
||||||
borderRadius: 16,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
marginLeft: 20,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: "700",
|
|
||||||
color: props.isSelected ? "white" : "black",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.name}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
{props.isSelected && (
|
|
||||||
<Entypo
|
|
||||||
style={{ marginRight: 8 }}
|
|
||||||
name="check"
|
|
||||||
size={20}
|
|
||||||
color="white"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</TouchableBounce>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { View, Text, Button } from "react-native";
|
|
||||||
import GoogleCast, {
|
|
||||||
CastState,
|
|
||||||
CastButton,
|
|
||||||
useCastState,
|
|
||||||
useRemoteMediaClient,
|
|
||||||
} from "react-native-google-cast";
|
|
||||||
|
|
||||||
export default function HomeScreen() {
|
|
||||||
const castState = useCastState();
|
|
||||||
const client = useRemoteMediaClient();
|
|
||||||
|
|
||||||
GoogleCast.showIntroductoryOverlay();
|
|
||||||
|
|
||||||
const isConnected = castState === CastState.CONNECTED;
|
|
||||||
|
|
||||||
function cast() {
|
|
||||||
client
|
|
||||||
.loadMedia({
|
|
||||||
mediaInfo: {
|
|
||||||
contentUrl:
|
|
||||||
"https://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/mp4/BigBuckBunny.mp4",
|
|
||||||
contentType: "video/mp4",
|
|
||||||
metadata: {
|
|
||||||
images: [
|
|
||||||
{
|
|
||||||
url:
|
|
||||||
"https://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/images/480x270/BigBuckBunny.jpg",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
title: "Big Buck Bunny",
|
|
||||||
subtitle:
|
|
||||||
"A large and lovable rabbit deals with three tiny bullies, led by a flying squirrel, who are determined to squelch his happiness.",
|
|
||||||
studio: "Blender Foundation",
|
|
||||||
type: "movie",
|
|
||||||
},
|
|
||||||
streamDuration: 596, // seconds
|
|
||||||
},
|
|
||||||
startTime: 10, // seconds
|
|
||||||
})
|
|
||||||
.then(console.log)
|
|
||||||
.catch(console.warn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
|
|
||||||
<Text>State: {castState}</Text>
|
|
||||||
<CastButton style={{ width: 24, height: 24 }} />
|
|
||||||
<Button
|
|
||||||
title="Overlay"
|
|
||||||
onPress={() => {
|
|
||||||
GoogleCast.showIntroductoryOverlay();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
title="Expanded Controls"
|
|
||||||
onPress={() => {
|
|
||||||
GoogleCast.showExpandedControls();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
title="Cast"
|
|
||||||
disabled={!isConnected}
|
|
||||||
onPress={() => {
|
|
||||||
cast();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
title="Pause"
|
|
||||||
disabled={!isConnected}
|
|
||||||
onPress={() => {
|
|
||||||
// cast()
|
|
||||||
client.pause();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
title="Disconnect"
|
|
||||||
disabled={!isConnected}
|
|
||||||
onPress={() => {
|
|
||||||
GoogleCast.sessionManager.endCurrentSession(true);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { SafeAreaView, StyleSheet, useWindowDimensions } from 'react-native';
|
|
||||||
import Pdf from 'react-native-pdf';
|
|
||||||
|
|
||||||
const source = {
|
|
||||||
uri: "https://samples.leanpub.com/thereactnativebook-sample.pdf",
|
|
||||||
cache: true,
|
|
||||||
};
|
|
||||||
export default function App() {
|
|
||||||
const { width, height } = useWindowDimensions()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SafeAreaView style={styles.container}>
|
|
||||||
<Pdf
|
|
||||||
source={source}
|
|
||||||
onLoadComplete={(numberOfPages, filePath) => {
|
|
||||||
console.log(`Number of pages: ${numberOfPages}`);
|
|
||||||
}}
|
|
||||||
onPageChanged={(page, numberOfPages) => {
|
|
||||||
console.log(`Current page: ${page}`);
|
|
||||||
}}
|
|
||||||
onError={(error) => {
|
|
||||||
console.log(error);
|
|
||||||
}}
|
|
||||||
onPressLink={(uri) => {
|
|
||||||
console.log(`Link pressed: ${uri}`);
|
|
||||||
}}
|
|
||||||
style={{ flex: 1, width, height }}
|
|
||||||
/>
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: "flex-start",
|
|
||||||
alignItems: "center",
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
import QuickActions from "react-native-quick-actions";
|
|
||||||
import React from "react";
|
|
||||||
import { Text, View } from "react-native";
|
|
||||||
|
|
||||||
import { DeviceEventEmitter } from "react-native";
|
|
||||||
|
|
||||||
function useQuickAction(): QuickActions.ShortcutItem | null {
|
|
||||||
const [item, setItem] = React.useState<QuickActions.ShortcutItem | null>(null);
|
|
||||||
const isMounted = React.useRef(true)
|
|
||||||
React.useEffect(() => {
|
|
||||||
QuickActions.popInitialAction().then(action => {
|
|
||||||
if (isMounted.current) setItem(action);
|
|
||||||
})
|
|
||||||
const sub = DeviceEventEmitter.addListener("quickActionShortcut", data => {
|
|
||||||
if (isMounted.current) {
|
|
||||||
setItem(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return () => {
|
|
||||||
isMounted.current = false;
|
|
||||||
sub.remove();
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
function App() {
|
|
||||||
const action = useQuickAction();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
QuickActions.setShortcutItems([
|
|
||||||
{
|
|
||||||
title: 'Play Song',
|
|
||||||
subtitle: 'NDA - Billie Eilish',
|
|
||||||
icon: 'Play',
|
|
||||||
type: 'alpha',
|
|
||||||
} as any,
|
|
||||||
{
|
|
||||||
title: 'Shuffle',
|
|
||||||
icon: 'Shuffle',
|
|
||||||
type: 'beta',
|
|
||||||
} as any,
|
|
||||||
{
|
|
||||||
title: 'Like Song',
|
|
||||||
icon: 'Love',
|
|
||||||
type: 'gamma',
|
|
||||||
} as any,
|
|
||||||
])
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
|
|
||||||
<Text>Quick Actions</Text>
|
|
||||||
{action && <Text>{JSON.stringify(action, null, 2)}</Text>}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default App;
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
import { Button, SafeAreaView, StatusBar, StyleSheet, View } from 'react-native';
|
|
||||||
import { mediaDevices, RTCView } from 'react-native-webrtc';
|
|
||||||
|
|
||||||
const App = () => {
|
|
||||||
const [stream, setStream] = useState(null);
|
|
||||||
const start = async () => {
|
|
||||||
console.log('start');
|
|
||||||
if (!stream) {
|
|
||||||
let s;
|
|
||||||
try {
|
|
||||||
s = await mediaDevices.getUserMedia({ video: true });
|
|
||||||
setStream(s);
|
|
||||||
} catch(e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const stop = () => {
|
|
||||||
console.log('stop');
|
|
||||||
if (stream) {
|
|
||||||
stream.release();
|
|
||||||
setStream(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<StatusBar barStyle="dark-content" />
|
|
||||||
<SafeAreaView style={styles.body}>
|
|
||||||
{
|
|
||||||
stream &&
|
|
||||||
<RTCView
|
|
||||||
streamURL={stream.toURL()}
|
|
||||||
style={styles.stream} />
|
|
||||||
}
|
|
||||||
<View
|
|
||||||
style={styles.footer}>
|
|
||||||
<Button
|
|
||||||
title = "Start"
|
|
||||||
onPress = {start} />
|
|
||||||
<Button
|
|
||||||
title = "Stop"
|
|
||||||
onPress = {stop} />
|
|
||||||
</View>
|
|
||||||
</SafeAreaView>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
body: {
|
|
||||||
...StyleSheet.absoluteFillObject
|
|
||||||
},
|
|
||||||
stream: {
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default App;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
const { createWebpackConfigAsync } = require("expo-yarn-workspaces/webpack");
|
|
||||||
|
|
||||||
module.exports = createWebpackConfigAsync;
|
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
import withAppleSettings, {
|
||||||
|
ChildPane,
|
||||||
|
Group,
|
||||||
|
RadioGroup,
|
||||||
|
Slider,
|
||||||
|
Switch,
|
||||||
|
TextField,
|
||||||
|
Title,
|
||||||
|
} from "@config-plugins/apple-settings";
|
||||||
|
import { MultiValue } from "@config-plugins/apple-settings/build/models";
|
||||||
|
import { ConfigContext, ExpoConfig } from "expo/config";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
const folderName = path.basename(__dirname);
|
||||||
|
const cleanName = folderName.replace(/[_\s-]/g, "");
|
||||||
|
const appId = "dev.bacon." + cleanName;
|
||||||
|
|
||||||
|
function withWhiteLabel(config: Partial<ExpoConfig>) {
|
||||||
|
if (!config.extra) config.extra = {};
|
||||||
|
// Expose CI env variables to the app
|
||||||
|
config.extra.CI = process.env.CI;
|
||||||
|
|
||||||
|
if (!config.ios) config.ios = {};
|
||||||
|
config.ios.bundleIdentifier = appId;
|
||||||
|
if (!config.android) config.android = {};
|
||||||
|
config.android.package = appId;
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ({ config }: ConfigContext): Partial<ExpoConfig> => {
|
||||||
|
config = withWhiteLabel(config);
|
||||||
|
|
||||||
|
config = withAppleSettings(config as ExpoConfig, {
|
||||||
|
// The name of the .plist file to generate. Root is the default and must be provided.
|
||||||
|
Root: {
|
||||||
|
// The locales object is optional. If provided, it will be used to generate the localized .strings files.
|
||||||
|
locales: {
|
||||||
|
// The Apple locale code. This will be used to generate the .strings file.
|
||||||
|
en: {
|
||||||
|
// Name of the localized key.
|
||||||
|
Name: "Text Field",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// The page object is required. It will be used to generate the .plist file.
|
||||||
|
// The contents will be converted directly to plist.
|
||||||
|
page: {
|
||||||
|
// The `PreferenceSpecifiers` defines the UI elements to generate.
|
||||||
|
PreferenceSpecifiers: [
|
||||||
|
Title({
|
||||||
|
title: "Title",
|
||||||
|
value: "Default Title",
|
||||||
|
key: "title_preference",
|
||||||
|
}),
|
||||||
|
// Helper models can be used to generate the UI elements using
|
||||||
|
// an API that's similar to React Native.
|
||||||
|
TextField({
|
||||||
|
title: "Name",
|
||||||
|
key: "name_preference",
|
||||||
|
value: "",
|
||||||
|
keyboardType: "Alphabet",
|
||||||
|
autoCapitalize: "None",
|
||||||
|
autoCorrect: "No",
|
||||||
|
}),
|
||||||
|
Switch({
|
||||||
|
title: "Enabled",
|
||||||
|
key: "enabled_preference",
|
||||||
|
value: true,
|
||||||
|
}),
|
||||||
|
Slider({
|
||||||
|
key: "slider_preference",
|
||||||
|
value: 0.5,
|
||||||
|
}),
|
||||||
|
// Broken https://forums.developer.apple.com/forums/thread/764519
|
||||||
|
// RadioGroup({
|
||||||
|
// value: "option1",
|
||||||
|
// key: "radio_preference",
|
||||||
|
// items: [
|
||||||
|
// {
|
||||||
|
// title: "Option 1",
|
||||||
|
// value: "option1",
|
||||||
|
// },
|
||||||
|
|
||||||
|
// {
|
||||||
|
// title: "Option 2",
|
||||||
|
// value: "option2",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// }),
|
||||||
|
// MultiValue({
|
||||||
|
// title: "Multi Value",
|
||||||
|
// key: "multi_value_preference",
|
||||||
|
// value: "alpha",
|
||||||
|
// items: [
|
||||||
|
// {
|
||||||
|
// title: "Alpha",
|
||||||
|
// value: "alpha",
|
||||||
|
// short: "α",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: "Beta",
|
||||||
|
// value: "beta",
|
||||||
|
// short: "β",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: "Delta",
|
||||||
|
// value: "delta",
|
||||||
|
// short: "Δ",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: "Omega",
|
||||||
|
// value: "omega",
|
||||||
|
// short: "Ω",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// }),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return config;
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "apple-settings",
|
||||||
|
"icon": "https://github.com/expo.png",
|
||||||
|
"platforms": ["ios"],
|
||||||
|
"plugins": [["expo-build-properties", { "ios": { "ccacheEnabled": true } }]]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { registerRootComponent } from "expo";
|
||||||
|
|
||||||
|
import App from "./src/App";
|
||||||
|
|
||||||
|
registerRootComponent(App);
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "@config-plugins-app/apple-settings",
|
||||||
|
"main": "./index.js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start --dev-client",
|
||||||
|
"ios": "expo run:ios",
|
||||||
|
"android": "expo run:android"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@config-plugins/apple-settings": "*",
|
||||||
|
"@react-native-community/slider": "4.5.6",
|
||||||
|
"@react-native-picker/picker": "2.11.0",
|
||||||
|
"expo": "~53",
|
||||||
|
"expo-splash-screen": "~0.30.7",
|
||||||
|
"react": "19.0.0",
|
||||||
|
"react-native": "0.79.2"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Button, Linking, StyleSheet, View } from "react-native";
|
||||||
|
|
||||||
|
import {
|
||||||
|
SettingsRadioGroup,
|
||||||
|
SettingsSlider,
|
||||||
|
SettingsSwitch,
|
||||||
|
SettingsTextInput,
|
||||||
|
SettingsTitle,
|
||||||
|
} from "./SettingsViews";
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
{/* <SettingsTitle settingsKey="title_preference" /> */}
|
||||||
|
<SettingsTextInput
|
||||||
|
style={{
|
||||||
|
height: 40,
|
||||||
|
borderColor: "gray",
|
||||||
|
borderWidth: 1,
|
||||||
|
padding: 8,
|
||||||
|
}}
|
||||||
|
settingsKey="name_preference"
|
||||||
|
/>
|
||||||
|
<SettingsSwitch settingsKey="enabled_preference" />
|
||||||
|
<SettingsSlider settingsKey="slider_preference" />
|
||||||
|
<View />
|
||||||
|
<SettingsRadioGroup settingsKey="radio_preference">
|
||||||
|
<SettingsRadioGroup.Item label="Option 1" value="option1" />
|
||||||
|
<SettingsRadioGroup.Item label="Option 2" value="option2" />
|
||||||
|
</SettingsRadioGroup>
|
||||||
|
<View />
|
||||||
|
<Button
|
||||||
|
title="Launch Settings"
|
||||||
|
onPress={() => {
|
||||||
|
Linking.openSettings();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "stretch",
|
||||||
|
paddingHorizontal: 56,
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
fontSize: 24,
|
||||||
|
marginVertical: 12,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default App;
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import Slider from "@react-native-community/slider";
|
||||||
|
import { Picker } from "@react-native-picker/picker";
|
||||||
|
import React from "react";
|
||||||
|
import { Settings, Switch, Text, TextInput } from "react-native";
|
||||||
|
|
||||||
|
export function useSetting<T = string>(key: string): [T, (value: T) => void] {
|
||||||
|
const [value, setValue] = React.useState<T>(() => Settings.get(key));
|
||||||
|
React.useEffect(() => {
|
||||||
|
let isMounted = true;
|
||||||
|
const callback = Settings.watchKeys(key, () => {
|
||||||
|
if (isMounted) {
|
||||||
|
setValue(Settings.get(key));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
Settings.clearWatch(callback);
|
||||||
|
isMounted = false;
|
||||||
|
};
|
||||||
|
}, [key]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
value,
|
||||||
|
(value) => {
|
||||||
|
Settings.set({ [key]: value });
|
||||||
|
setValue(value);
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingsSlider({
|
||||||
|
settingsKey,
|
||||||
|
...props
|
||||||
|
}: { settingsKey: string } & Omit<
|
||||||
|
React.ComponentProps<typeof Slider>,
|
||||||
|
"selectedValue" | "onValueChange"
|
||||||
|
>) {
|
||||||
|
const [value, setValue] = useSetting<number>(settingsKey);
|
||||||
|
return <Slider {...props} value={value ?? 0} onValueChange={setValue} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingsRadioGroup({
|
||||||
|
settingsKey,
|
||||||
|
...props
|
||||||
|
}: { settingsKey: string } & Omit<
|
||||||
|
React.ComponentProps<typeof Picker>,
|
||||||
|
"selectedValue" | "onValueChange"
|
||||||
|
>) {
|
||||||
|
const [value, setValue] = useSetting<string>(settingsKey);
|
||||||
|
return (
|
||||||
|
<Picker
|
||||||
|
{...props}
|
||||||
|
selectedValue={value ?? "option1"}
|
||||||
|
onValueChange={setValue}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsRadioGroup.Item = Picker.Item;
|
||||||
|
|
||||||
|
export function SettingsSwitch({
|
||||||
|
settingsKey,
|
||||||
|
...props
|
||||||
|
}: { settingsKey: string } & Omit<
|
||||||
|
React.ComponentProps<typeof Switch>,
|
||||||
|
"value" | "onValueChange"
|
||||||
|
>) {
|
||||||
|
const [value, setValue] = useSetting<boolean>(settingsKey);
|
||||||
|
return <Switch {...props} value={!!value} onValueChange={setValue} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingsTitle({
|
||||||
|
settingsKey,
|
||||||
|
...props
|
||||||
|
}: { settingsKey: string } & Omit<
|
||||||
|
React.ComponentProps<typeof Text>,
|
||||||
|
"children"
|
||||||
|
>) {
|
||||||
|
const [value] = useSetting<string>(settingsKey);
|
||||||
|
return <Text {...props} children={value} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingsTextInput({
|
||||||
|
settingsKey,
|
||||||
|
...props
|
||||||
|
}: { settingsKey: string } & Omit<
|
||||||
|
React.ComponentProps<typeof TextInput>,
|
||||||
|
"value" | "onChangeText"
|
||||||
|
>) {
|
||||||
|
const [value, setValue] = useSetting<string>(settingsKey);
|
||||||
|
return <TextInput {...props} value={value} onChangeText={setValue} />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {},
|
||||||
|
"extends": "expo/tsconfig.base"
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const folderName = path.basename(__dirname);
|
||||||
|
const cleanName = folderName.replace(/[_\s-]/g, "");
|
||||||
|
const appId = "dev.bacon." + cleanName;
|
||||||
|
|
||||||
|
module.exports = ({ config }) => {
|
||||||
|
if (!config.extra) config.extra = {};
|
||||||
|
// Expose CI env variables to the app
|
||||||
|
config.extra.CI = process.env.CI;
|
||||||
|
|
||||||
|
if (!config.ios) config.ios = {};
|
||||||
|
config.ios.bundleIdentifier = appId;
|
||||||
|
if (!config.android) config.android = {};
|
||||||
|
config.android.package = appId;
|
||||||
|
return config;
|
||||||
|
};
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "ffmpeg",
|
||||||
|
"icon": "https://github.com/expo.png",
|
||||||
|
"splash": {
|
||||||
|
"image": "https://github.com/expo.png"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"@config-plugins/ffmpeg-kit-react-native",
|
||||||
|
{
|
||||||
|
"package": "min"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { registerRootComponent } from "expo";
|
||||||
|
|
||||||
|
import App from "./src/App";
|
||||||
|
|
||||||
|
registerRootComponent(App);
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@config-plugins-app/ffmpeg-kit-react-native",
|
||||||
|
"main": "./index.js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start --dev-client",
|
||||||
|
"ios": "expo run:ios",
|
||||||
|
"android": "expo run:android"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@config-plugins/ffmpeg-kit-react-native": "*",
|
||||||
|
"expo": "~53",
|
||||||
|
"expo-splash-screen": "~0.30.7",
|
||||||
|
"ffmpeg-kit-react-native": "^6.0.2",
|
||||||
|
"react": "19.0.0",
|
||||||
|
"react-native": "0.79.2"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { Session } from "ffmpeg-kit-react-native";
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
SafeAreaView,
|
||||||
|
ScrollView,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
import { useMediaInfo, useResolvedValue } from "./useMediaInfo";
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
const session = useMediaInfo(
|
||||||
|
"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ActivityIndicator />
|
||||||
|
<Text>Loading...</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <SessionInfo session={session} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SessionInfo(props: { session: Session }) {
|
||||||
|
const { session } = props;
|
||||||
|
const duration = useResolvedValue(session.getDuration.bind(session));
|
||||||
|
const output = useResolvedValue(session.getOutput.bind(session));
|
||||||
|
return (
|
||||||
|
<SafeAreaView
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ScrollView>
|
||||||
|
<Text>Duration: {duration}</Text>
|
||||||
|
<Text>Output: {output}</Text>
|
||||||
|
</ScrollView>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {},
|
||||||
|
"extends": "expo/tsconfig.base"
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const folderName = path.basename(__dirname);
|
||||||
|
const cleanName = folderName.replace(/[_\s-]/g, "");
|
||||||
|
const appId = "dev.bacon." + cleanName;
|
||||||
|
|
||||||
|
module.exports = ({ config }) => {
|
||||||
|
if (!config.extra) config.extra = {};
|
||||||
|
// Expose CI env variables to the app
|
||||||
|
config.extra.CI = process.env.CI;
|
||||||
|
|
||||||
|
if (!config.ios) config.ios = {};
|
||||||
|
config.ios.bundleIdentifier = appId;
|
||||||
|
if (!config.android) config.android = {};
|
||||||
|
config.android.package = appId;
|
||||||
|
return config;
|
||||||
|
};
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "stickers",
|
||||||
|
"icon": "https://github.com/expo.png",
|
||||||
|
"platforms": ["ios"],
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"@config-plugins/ios-stickers",
|
||||||
|
{
|
||||||
|
"name": "Stickers",
|
||||||
|
"stickerBundleId": "dev.bacon.iosstickers.stickers",
|
||||||
|
"icon": "./assets/imessage-icon.png",
|
||||||
|
"columns": 4,
|
||||||
|
"stickers": [
|
||||||
|
"./assets/stickers/annoyed.png",
|
||||||
|
"./assets/stickers/cuddle.png",
|
||||||
|
"./assets/stickers/crazy.png",
|
||||||
|
"./assets/stickers/cant.png",
|
||||||
|
"./assets/stickers/donno.png",
|
||||||
|
"./assets/stickers/cozzy.png",
|
||||||
|
"./assets/stickers/dork.png",
|
||||||
|
"./assets/stickers/focus.png",
|
||||||
|
"./assets/stickers/avocool.png",
|
||||||
|
"./assets/stickers/coder-girl.png",
|
||||||
|
"./assets/stickers/teapot.png"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
["expo-build-properties", { "ios": { "ccacheEnabled": true } }]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 179 KiB |
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
import { registerRootComponent } from "expo";
|
||||||
|
|
||||||
|
import App from "./src/App";
|
||||||
|
|
||||||
|
registerRootComponent(App);
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@config-plugins-app/ios-stickers",
|
||||||
|
"main": "./index.js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start --dev-client",
|
||||||
|
"prebuild": "expo prebuild -p ios --template ./expo-template-bare-minimum-50.0.17.tgz",
|
||||||
|
"ios": "expo run:ios",
|
||||||
|
"android": "expo run:android"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@config-plugins/ios-stickers": "*",
|
||||||
|
"expo": "~53",
|
||||||
|
"expo-splash-screen": "~0.30.7",
|
||||||
|
"react": "19.0.0",
|
||||||
|
"react-native": "0.79.2"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { Text, View } from "react-native";
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
|
||||||
|
<Text>Open iMessage to find the app</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const folderName = path.basename(__dirname);
|
||||||
|
const cleanName = folderName.replace(/[_\s-]/g, "");
|
||||||
|
const appId = "dev.bacon." + cleanName;
|
||||||
|
|
||||||
|
module.exports = ({ config }) => {
|
||||||
|
if (!config.extra) config.extra = {};
|
||||||
|
// Expose CI env variables to the app
|
||||||
|
config.extra.CI = process.env.CI;
|
||||||
|
|
||||||
|
if (!config.ios) config.ios = {};
|
||||||
|
config.ios.bundleIdentifier = appId;
|
||||||
|
if (!config.android) config.android = {};
|
||||||
|
config.android.package = appId;
|
||||||
|
return config;
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "branch",
|
||||||
|
"icon": "https://github.com/expo.png",
|
||||||
|
"splash": {
|
||||||
|
"image": "https://github.com/expo.png"
|
||||||
|
},
|
||||||
|
"ios": {
|
||||||
|
"config": {
|
||||||
|
"branch": {
|
||||||
|
"apiKey": "key_live_f9f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"config": {
|
||||||
|
"branch": {
|
||||||
|
"apiKey": "key_live_f9f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"@config-plugins/react-native-branch",
|
||||||
|
["expo-build-properties", { "ios": { "ccacheEnabled": true } }]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { registerRootComponent } from "expo";
|
||||||
|
|
||||||
|
import App from "./src/App";
|
||||||
|
|
||||||
|
registerRootComponent(App);
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@config-plugins-app/react-native-branch",
|
||||||
|
"main": "./index.js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start --dev-client",
|
||||||
|
"ios": "expo run:ios",
|
||||||
|
"android": "expo run:android"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@config-plugins/react-native-branch": "*",
|
||||||
|
"expo": "~53",
|
||||||
|
"expo-splash-screen": "~0.30.7",
|
||||||
|
"react": "19.0.0",
|
||||||
|
"react-native": "0.79.2",
|
||||||
|
"react-native-branch": "^6.6.0"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { Text, View } from "react-native";
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
|
||||||
|
<Text>Branch</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const folderName = path.basename(__dirname);
|
||||||
|
const cleanName = folderName.replace(/[_\s-]/g, "");
|
||||||
|
const appId = "dev.bacon." + cleanName;
|
||||||
|
|
||||||
|
module.exports = ({ config }) => {
|
||||||
|
if (!config.extra) config.extra = {};
|
||||||
|
// Expose CI env variables to the app
|
||||||
|
config.extra.CI = process.env.CI;
|
||||||
|
|
||||||
|
if (!config.ios) config.ios = {};
|
||||||
|
config.ios.bundleIdentifier = appId;
|
||||||
|
if (!config.android) config.android = {};
|
||||||
|
config.android.package = appId;
|
||||||
|
return config;
|
||||||
|
};
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "app-icon",
|
||||||
|
"icon": "./assets/icons/winter.png",
|
||||||
|
"platforms": ["ios"],
|
||||||
|
"ios": {
|
||||||
|
"supportsTablet": true
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"@config-plugins/react-native-dynamic-app-icon",
|
||||||
|
[
|
||||||
|
"./assets/icons/spring.png",
|
||||||
|
"./assets/icons/summer.png",
|
||||||
|
"./assets/icons/autumn.png",
|
||||||
|
"./assets/icons/fall.png",
|
||||||
|
"./assets/icons/solstice.png"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
["expo-build-properties", { "ios": { "ccacheEnabled": true } }]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
import { registerRootComponent } from "expo";
|
||||||
|
|
||||||
|
import App from "./src/App";
|
||||||
|
|
||||||
|
registerRootComponent(App);
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@config-plugins-app/react-native-dynamic-app-icon",
|
||||||
|
"main": "./index.js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start --dev-client",
|
||||||
|
"ios": "expo run:ios",
|
||||||
|
"android": "expo run:android"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@config-plugins/react-native-dynamic-app-icon": "*",
|
||||||
|
"expo": "~53",
|
||||||
|
"expo-splash-screen": "~0.30.7",
|
||||||
|
"react": "19.0.0",
|
||||||
|
"react-native": "0.79.2",
|
||||||
|
"react-native-dynamic-app-icon": "^1.1.0"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
import Entypo from "@expo/vector-icons/Entypo";
|
||||||
|
import React from "react";
|
||||||
|
import { Image, SafeAreaView, Text, View } from "react-native";
|
||||||
|
import AppIcon from "react-native-dynamic-app-icon";
|
||||||
|
import TouchableBounce from "react-native/Libraries/Components/Touchable/TouchableBounce";
|
||||||
|
|
||||||
|
function useIconName() {
|
||||||
|
const [icon, _setIcon] = React.useState(null);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
let isMounted = true;
|
||||||
|
AppIcon.getIconName((result) => {
|
||||||
|
if (isMounted) _setIcon(result.iconName);
|
||||||
|
});
|
||||||
|
return () => (isMounted = false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const setIcon = React.useCallback(
|
||||||
|
(icon) => {
|
||||||
|
AppIcon.setAppIcon(icon);
|
||||||
|
_setIcon(icon || null);
|
||||||
|
},
|
||||||
|
[_setIcon]
|
||||||
|
);
|
||||||
|
return [icon === "default" ? null : icon, setIcon];
|
||||||
|
}
|
||||||
|
|
||||||
|
const icons = [
|
||||||
|
{
|
||||||
|
name: "Auto",
|
||||||
|
source: require("../assets/icons/winter.png"),
|
||||||
|
iconId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Spring",
|
||||||
|
source: require("../assets/icons/spring.png"),
|
||||||
|
iconId: "0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Summer",
|
||||||
|
source: require("../assets/icons/summer.png"),
|
||||||
|
iconId: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Autumn",
|
||||||
|
source: require("../assets/icons/autumn.png"),
|
||||||
|
iconId: "2",
|
||||||
|
},
|
||||||
|
{ name: "Fall", source: require("../assets/icons/fall.png"), iconId: "3" },
|
||||||
|
{
|
||||||
|
name: "Solstice",
|
||||||
|
source: require("../assets/icons/solstice.png"),
|
||||||
|
iconId: "4",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
const [_icon, setIcon] = useIconName();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View style={{ width: "100%" }}>
|
||||||
|
{icons.map((icon, index) => {
|
||||||
|
return (
|
||||||
|
<Item
|
||||||
|
onPress={() => {
|
||||||
|
setIcon(icon.iconId);
|
||||||
|
}}
|
||||||
|
isSelected={icon.iconId === _icon}
|
||||||
|
name={icon.name}
|
||||||
|
source={icon.source}
|
||||||
|
key={String(index)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Item({ ...props }) {
|
||||||
|
return (
|
||||||
|
<TouchableBounce
|
||||||
|
onPress={props.onPress}
|
||||||
|
style={{ marginVertical: 8, marginHorizontal: 24 }}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "stretch",
|
||||||
|
shadowColor: "#000",
|
||||||
|
shadowOffset: {
|
||||||
|
width: 0,
|
||||||
|
height: 4,
|
||||||
|
},
|
||||||
|
shadowOpacity: props.isSelected ? 0.35 : 0.2,
|
||||||
|
shadowRadius: 8.46,
|
||||||
|
|
||||||
|
backgroundColor: props.isSelected ? "#000" : "#F1F1F1",
|
||||||
|
elevation: 9,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 12,
|
||||||
|
borderRadius: 20,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
flex: 1,
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
flex: 1,
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
source={props.source}
|
||||||
|
style={{
|
||||||
|
width: 64,
|
||||||
|
aspectRatio: 1,
|
||||||
|
resizeMode: "cover",
|
||||||
|
borderRadius: 16,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
marginLeft: 20,
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: "700",
|
||||||
|
color: props.isSelected ? "white" : "black",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.name}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
{props.isSelected && (
|
||||||
|
<Entypo
|
||||||
|
style={{ marginRight: 8 }}
|
||||||
|
name="check"
|
||||||
|
size={20}
|
||||||
|
color="white"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</TouchableBounce>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {},
|
||||||
|
"extends": "expo/tsconfig.base"
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const folderName = path.basename(__dirname);
|
||||||
|
const cleanName = folderName.replace(/[_\s-]/g, "");
|
||||||
|
const appId = "dev.bacon." + cleanName;
|
||||||
|
|
||||||
|
module.exports = ({ config }) => {
|
||||||
|
if (!config.extra) config.extra = {};
|
||||||
|
// Expose CI env variables to the app
|
||||||
|
config.extra.CI = process.env.CI;
|
||||||
|
|
||||||
|
if (!config.ios) config.ios = {};
|
||||||
|
config.ios.bundleIdentifier = appId;
|
||||||
|
if (!config.android) config.android = {};
|
||||||
|
config.android.package = appId;
|
||||||
|
return config;
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "pdf",
|
||||||
|
"icon": "https://github.com/expo.png",
|
||||||
|
"splash": {
|
||||||
|
"image": "https://github.com/expo.png"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"@config-plugins/react-native-blob-util",
|
||||||
|
"@config-plugins/react-native-pdf",
|
||||||
|
["expo-build-properties", { "ios": { "ccacheEnabled": true } }]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { registerRootComponent } from "expo";
|
||||||
|
|
||||||
|
import App from "./src/App";
|
||||||
|
|
||||||
|
registerRootComponent(App);
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "@config-plugins-app/react-native-pdf",
|
||||||
|
"main": "./index.js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start --dev-client",
|
||||||
|
"ios": "expo run:ios",
|
||||||
|
"android": "expo run:android"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@config-plugins/react-native-blob-util": "*",
|
||||||
|
"@config-plugins/react-native-pdf": "*",
|
||||||
|
"expo": "~53",
|
||||||
|
"expo-splash-screen": "~0.30.7",
|
||||||
|
"react": "19.0.0",
|
||||||
|
"react-native": "0.79.2",
|
||||||
|
"react-native-blob-util": "^0.21.2",
|
||||||
|
"react-native-pdf": "^6.7.7"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { SafeAreaView, StyleSheet, useWindowDimensions } from "react-native";
|
||||||
|
import Pdf from "react-native-pdf";
|
||||||
|
|
||||||
|
const source = {
|
||||||
|
uri: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
|
||||||
|
cache: true,
|
||||||
|
};
|
||||||
|
export default function App() {
|
||||||
|
const { width, height } = useWindowDimensions();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={styles.container}>
|
||||||
|
<Pdf
|
||||||
|
trustAllCerts={false}
|
||||||
|
source={source}
|
||||||
|
onLoadComplete={(numberOfPages, filePath) => {
|
||||||
|
console.log(`Number of pages: ${numberOfPages}`);
|
||||||
|
}}
|
||||||
|
onPageChanged={(page, numberOfPages) => {
|
||||||
|
console.log(`Current page: ${page}`);
|
||||||
|
}}
|
||||||
|
onError={(error) => {
|
||||||
|
console.log(error);
|
||||||
|
}}
|
||||||
|
onPressLink={(uri) => {
|
||||||
|
console.log(`Link pressed: ${uri}`);
|
||||||
|
}}
|
||||||
|
style={{ flex: 1, width, height }}
|
||||||
|
/>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
});
|
||||||