Compare commits

..
Author SHA1 Message Date
Evan Bacon 754fb08327 Merge branch 'master' into @evanbacon/e2e-tests 2021-12-14 21:13:34 -07:00
Evan Bacon 05fe7bf107 Update package.json 2021-11-30 13:34:25 -07:00
Evan Bacon fa107895b6 Update detox.config.js 2021-11-29 17:18:39 -07:00
Evan Bacon d31b0273cf [WIP][NO-MERGE] 2021-11-29 17:01:02 -07:00
Evan Bacon 2f358c25e8 Try new monorepo imports 2021-11-29 16:30:21 -07:00
Evan Bacon d2eb511e1d Update e2e.yml 2021-11-29 14:38:53 -07:00
Evan Bacon f62a941bc6 Update e2e.yml 2021-11-29 14:38:30 -07:00
Evan Bacon d784d14486 Update app.json 2021-11-29 11:44:27 -07:00
Evan Bacon 7b0d0225f9 Update yarn.lock 2021-11-29 11:43:49 -07:00
Evan Bacon c1d25701ca Merge branch 'master' into @evanbacon/e2e-tests 2021-11-29 11:43:10 -07:00
Evan Bacon 5359120dbd Improved CI 2021-07-03 18:43:11 -06:00
Evan Bacon ed6b3a0ec0 Update detox.config.js 2021-07-03 18:30:03 -06:00
Evan Bacon efd3284272 remove webrtc and google chrome 2021-07-03 18:19:46 -06:00
Evan Bacon 46bc48726c Update App-e2e.ts 2021-07-03 18:00:57 -06:00
Evan Bacon ff47e492e4 Update App-e2e.ts 2021-07-03 17:40:47 -06:00
Evan Bacon be969274b9 Update app.json 2021-07-03 17:21:36 -06:00
Evan Bacon 359c1cfcb5 added missing resize mode 2021-07-03 17:15:17 -06:00
Evan Bacon 6c3fc5dff7 Update e2e.yml 2021-07-03 17:12:56 -06:00
Evan Bacon 99d3927680 Update e2e.yml 2021-07-03 17:06:40 -06:00
Evan Bacon 55482dae5f Create .ruby-version 2021-07-03 17:04:15 -06:00
Evan Bacon 395599abfa Added e2e tests 2021-07-03 16:59:15 -06:00
366 changed files with 14696 additions and 15904 deletions

No files matched your search

-1
View File
@@ -1 +0,0 @@
/* @EvanBacon
-81
View File
@@ -1,81 +0,0 @@
name: 🐛 Expo Config Plugin Bug Report
description: Report a reproducible bug with one of the Expo Config Plugins.
labels: bug
body:
- type: markdown
attributes:
value: >-
Thanks for taking the time to file a bug report! Please fill out this
form as completely as possible.
- type: markdown
attributes:
value: >-
If you leave out sections there is a high likelihood your issue will be
closed. If you have a question, not a bug report, please post it on our
[forums](https://forums.expo.dev/) instead.
- type: textarea
attributes:
label: Summary
description: Describe the issue in 1 or 2 sentences
placeholder: >-
Clearly describe what the expected behavior is vs. what is actually
happening. This should be as short as possible, while still
communicating all the necessary information. If your summary is just 'X
library/method isn't working', then you need to continue debugging
yourself and provide more information.
validations:
required: true
- type: dropdown
attributes:
label: Config Plugin
options:
- '@config-plugins/android-jsc-intl'
- '@config-plugins/apple-settings'
- '@config-plugins/detox'
- '@config-plugins/ffmpeg-kit-react-native'
- '@config-plugins/ios-stickers'
- '@config-plugins/react-native-adjust'
- '@config-plugins/react-native-blob-util'
- '@config-plugins/react-native-branch'
- '@config-plugins/react-native-callkeep'
- '@config-plugins/react-native-dynamic-app-icon'
- '@config-plugins/react-native-pdf'
- '@config-plugins/react-native-siri-shortcut'
- '@config-plugins/react-native-webrtc'
validations:
required: true
- type: dropdown
attributes:
label: What platform(s) does this occur on?
multiple: true
options:
- Android
- iOS
validations:
required: true
- type: input
attributes:
label: SDK Version
description: What version of the Expo SDK are you using?
- type: textarea
attributes:
label: Reproducible demo
description: >-
This should include as little code as possible, do not simply link your
entire project. If a reproducible demo is not provided, it is very
likely your issue will be closed. Read [here more
guidance](https://stackoverflow.com/help/mcve).
validations:
required: true
- type: markdown
attributes:
value: >-
Please make sure contributors can run your code and follow the steps
your provided in order to reproduce the bug.
- type: markdown
attributes:
value: >-
**Realize that it is up to you to debug your code and be as certain as
possible that the bug is with Expo, not with your own app.** [Here's an
excellent guide to debugging you can
follow](https://gist.github.com/brentvatne/5ac00cba0c70b7a06b89a56787d6bc4a).
-37
View File
@@ -1,37 +0,0 @@
---
blank_issues_enabled: false
contact_links:
- name: 🤔 Question about an Expo Config Plugin
about: >-
If you have a question about an Expo Config Plugin, please ask it on the
forums, discord, Twitter, or Stack Overflow.
url: https://forums.expo.io/
- about: E2E tests and automation for mobile
name: 📦 detox issues
url: https://github.com/wix/Detox/issues
- about: FFmpeg Kit for React Native
name: 📦 ffmpeg-kit-react-native issues
url: https://github.com/arthenica/ffmpeg-kit/issues
- about: Adjust React Native SDK
name: 📦 react-native-adjust issues
url: https://github.com/adjust/react_native_sdk/issues
- about: >-
A module provides upload, download, and files access API. Supports file
stream read/write for process large files.
name: 📦 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
name: 📦 react-native-callkeep issues
url: https://github.com/react-native-webrtc/react-native-callkeep/issues
- about: Programmatically change the app icon in React Native.
name: 📦 react-native-dynamic-app-icon issues
url: https://github.com/idearockers/react-native-dynamic-app-icon/issues
- about: A react native PDF view component, support ios and android platform
name: 📦 react-native-pdf issues
url: https://github.com/wonday/react-native-pdf/issues
- about: A React Native library that enables you to use iOS 12+ Siri Shortcuts.
name: 📦 react-native-siri-shortcut issues
url: https://github.com/Gustash/react-native-siri-shortcut/issues
- about: WebRTC for React Native
name: 📦 react-native-webrtc issues
url: https://github.com/react-native-webrtc/react-native-webrtc/issues
-22
View File
@@ -1,22 +0,0 @@
name: "⭐️ Config Plugin Request"
description: "Suggest an idea for a new Expo Config Plugin."
labels: enhancement
body:
- type: markdown
attributes:
value: "This repo is used for publishing out-of-tree plugins that should eventually be upstreamed in a particular package. If the plugin is a utility or used to improve some particular workflow i.e. updates version numbers, than it's probably better suited for a personal repo or utility package."
- type: input
attributes:
label: Library
description: What package does this Config Plugin configure.
placeholder: URL to a React Native package.
validations:
required: true
- type: textarea
attributes:
label: Summary
description: Add some info on why this integration is important.
- type: textarea
attributes:
label: Any existing examples?
placeholder: Have you already created a local plugin for the requested library?
-24
View File
@@ -1,24 +0,0 @@
<!--
🚨 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.
-->
+155
View File
@@ -0,0 +1,155 @@
name: E2E Test
on:
workflow_dispatch: {}
push:
branches: [master]
paths:
- .github/workflows/ios.yml
- apps/app/**
- packages/**
- yarn.lock
pull_request:
paths:
- .github/workflows/ios.yml
- apps/app/**
- packages/**
- yarn.lock
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: true
jobs:
ios:
runs-on: macos-latest
steps:
- name: 👀 Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: 🍺 Install required tools
run: |
brew tap wix/brew
brew install applesimutils
brew install watchman
echo "$(pwd)/bin" >> $GITHUB_PATH
- name: 💎 Setup Ruby and install gems
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: ♻️ Restore workspace node modules
uses: actions/cache@v2
id: node-modules-cache
with:
path: |
# See "workspaces" → "packages" in the root package.json for the source of truth of
# which node_modules are affected by the root yarn.lock
node_modules
apps/*/node_modules
packages/*/node_modules
key: ${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }}
- name: 🧶 Install node modules in root dir
run: yarn install --frozen-lockfile
- name: ♻️ Restore apps/app/ios/Pods from cache
uses: actions/cache@v2
id: pods-cache
with:
path: "apps/app/ios/Pods"
key: ${{ runner.os }}-app-pods-${{ hashFiles('apps/app/ios/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-app-pods-
- run: yarn global add expo-cli
- name: 🔨 Prebuild
run: expo prebuild -p ios
working-directory: apps/app
- name: 🕵️ Debug CocoaPods lockfiles
run: git diff Podfile.lock Pods/Manifest.lock
working-directory: apps/app/ios
continue-on-error: true
- name: ⚛️ Display React Native config
run: yarn react-native config
working-directory: apps/app
- name: 🌳 Display pod environment
run: pod env
working-directory: apps/app/ios
- name: 🥥 Install pods in apps/app/ios
run: pod install
if: steps.pods-cache.outputs.cache-hit != 'true' || hashFiles('apps/app/ios/Podfile.lock') != hashFiles('apps/app/ios/Pods/Manifest.lock')
working-directory: apps/app/ios
- name: Clean Detox
run: yarn detox:clean
working-directory: apps/app
- name: Build iOS project for Detox
run: yarn build:ios-release
working-directory: apps/app
timeout-minutes: 30
- name: Run tests
run: yarn test:ios-release
working-directory: apps/app
- name: Store images of build failures
if: always()
uses: actions/upload-artifact@v2
with:
name: app-artifacts
path: apps/app/artifacts
android:
runs-on: macos-latest
steps:
- name: 👀 Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: 🍺 Install required tools
run: |
brew install watchman
echo "$(pwd)/bin" >> $GITHUB_PATH
- name: ♻️ Restore workspace node modules
uses: actions/cache@v2
id: node-modules-cache
with:
path: |
# See "workspaces" → "packages" in the root package.json for the source of truth of
# which node_modules are affected by the root yarn.lock
node_modules
apps/*/node_modules
packages/*/node_modules
key: ${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }}
- name: 🧶 Install node modules in root dir
run: yarn install --frozen-lockfile
- uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-v20210625-${{ hashFiles('android/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-v20210625
- run: yarn global add expo-cli
- name: 🔨 Prebuild
run: expo prebuild -p android
working-directory: apps/app
- name: ⚛️ Display React Native config
run: yarn react-native config
working-directory: apps/app
- name: Clean Detox
run: yarn detox:clean
working-directory: apps/app
- name: Build Android project for Detox
run: yarn build:android-release
working-directory: apps/app
timeout-minutes: 35
env:
GRADLE_OPTS: "-Dorg.gradle.internal.http.connectionTimeout=180000 -Dorg.gradle.internal.http.socketTimeout=180000 -Dorg.gradle.internal.network.retry.max.attempts=18 -Dorg.gradle.internal.network.retry.initial.backOff=2000"
- name: Run tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 29
avd-name: app
script: yarn test:android-release
working-directory: ./apps/app
- name: Store images of build failures
if: always()
uses: actions/upload-artifact@v2
with:
name: app-artifacts
path: apps/app/artifacts
+2 -2
View File
@@ -2,7 +2,7 @@ name: Check Markdown links
on:
workflow_dispatch: {}
push:
branches: [main]
branches: [master]
paths:
- .github/workflows/lint-md.yml
- "**.md"
@@ -16,5 +16,5 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn install --frozen-lockfile --check-files
- run: npm install
- run: npx remark --use validate-links . .github
+9 -13
View File
@@ -1,7 +1,7 @@
name: Test Packages
on:
push:
branches: [main]
branches: [master]
pull_request:
types: [opened, synchronize]
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: ["18"]
node: ["16", "17"]
name: Build with Node ${{ matrix.node }}
steps:
- uses: actions/checkout@v2
@@ -22,7 +22,7 @@ jobs:
node-version: ${{ matrix.node }}
- run: yarn install --frozen-lockfile --check-files
- run: yarn lerna run prepare --stream
- uses: actions/cache@v4
- uses: actions/cache@v2
with:
path: "*"
key: v2-${{ github.sha }}-${{ matrix.node }}
@@ -32,20 +32,20 @@ jobs:
strategy:
fail-fast: false
matrix:
node: ["18"]
node: ["16", "17"]
package: [
# Manually add packages here
detox,
ffmpeg-kit-react-native,
ios-stickers,
react-native-ble-plx,
react-native-blob-util,
react-native-branch,
react-native-siri-shortcut,
react-native-google-cast,
react-native-pdf,
# react-native-quick-actions,
]
name: Test ${{ matrix.package }} on Node ${{ matrix.node }}
steps:
- uses: actions/cache@v4
- uses: actions/cache@v2
with:
path: "*"
key: v2-${{ github.sha }}-${{ matrix.node }}
@@ -53,12 +53,8 @@ jobs:
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
- name: Lint ${{ matrix.package }}
run: yarn lint --max-warnings 0
working-directory: packages/${{ matrix.package }}
- name: Test ${{ matrix.package }}
run: yarn test
working-directory: packages/${{ matrix.package }}
run: cd packages/${{ matrix.package }} && yarn test
env:
CI: true
EXPO_DEBUG: true
+1 -13
View File
@@ -51,16 +51,4 @@ xcuserdata
# VSCode
.history/
# Ignore build folders
packages/*/build/**
packages/*/plugin/build/**
packages/@*/*/build/**
# App native folders
apps/*/ios/*
apps/*/android/*
apps/*/web-build/*
apps/*/dist/*
# packages/*/build/
+1
View File
@@ -0,0 +1 @@
2.7.0
-27
View File
@@ -1,27 +0,0 @@
# Contributing to Expo Config Plugins
## Submitting 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/`.)
2. Run `yarn` in the root directory to generate the build files.
3. Use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) including in the PR title.
4. Fill out the entire PR template. Ensure your code is tested locally and has continuous tests in CI.
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
All publishing should be handled automatically whenever code is merged to `main`.
+5 -64
View File
@@ -1,69 +1,10 @@
# Expo Config Plugins
- 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.
A collection of custom WIP config plugins for Expo dev clients. Use at your own discretion.
## First-party plugins
Here is a list of known packages that have a built-in Config Plugin.
## Creating a plugin
> Not all packages need a config plugin, packages that don't appear here might still work with managed EAS.
- [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).
- 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.
+4
View File
@@ -0,0 +1,4 @@
{
"12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
"40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
}
+79 -1
View File
@@ -1,2 +1,80 @@
node_modules/**/*
.expo/*
npm-debug.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/
# macOS
.DS_Store
/artifacts
/scripts/start.command
/artifacts
/ios
/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
+8 -3
View File
@@ -1,3 +1,8 @@
export { default } from "./src/detox/App";
// export { default } from "./src/android-jsc-intl/App";
// export { default } from "./src/react-native-adjust/App";
// export { default } from './src/react-native-quick-actions/App';
// export { default } from './src/react-native-dynamic-app-icon/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';
+8 -10
View File
@@ -1,10 +1,10 @@
{
"expo": {
"name": "detoxapp",
"name": "app",
"slug": "app",
"version": "1.0.0",
"orientation": "portrait",
"icon": "https://github.com/expo.png",
"icon": "./assets/icons/winter.png",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
@@ -13,10 +13,12 @@
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": ["**/*"],
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true,
"bundleIdentifier": "dev.bacon.app"
"bundleIdentifier": "com.bacon.app"
},
"android": {
"adaptiveIcon": {
@@ -29,11 +31,7 @@
"favicon": "./assets/favicon.png"
},
"plugins": [
"@config-plugins/detox",
"@config-plugins/react-native-adjust",
"@config-plugins/react-native-callkeep",
"@config-plugins/android-jsc-intl",
"expo-localization"
"@config-plugins/detox"
]
}
}
}
File renamed without changes.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 173 KiB

After

Width:  |  Height:  |  Size: 173 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 145 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 130 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 230 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 141 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 177 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 179 KiB

After

Width:  |  Height:  |  Size: 179 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 157 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 182 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 164 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 176 KiB

+6
View File
@@ -0,0 +1,6 @@
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};
+7 -15
View File
@@ -1,21 +1,13 @@
const iosName = "detoxapp";
const simulator = "iPhone 16";
const iosName = "app";
const emulator = process.env.CI ? "app" : "Pixel_3a_API_30";
const simulator = "iPhone 11";
const derivedDataPath = "ios/build";
const sdk = "iphonesimulator";
module.exports = {
testRunner: {
$0: "jest",
args: {
config: require.resolve("./e2e/jest.config.js"),
_: ["e2e"],
},
jest: {
setupTimeout: 300000,
reportSpecs: true,
reportWorkerAssign: true,
},
},
testRunner: "jest",
runnerConfig: require.resolve("./e2e/jest.config.js"),
specs: "e2e",
behavior: {
init: {
exposeGlobals: false,
@@ -55,7 +47,7 @@ module.exports = {
emulator: {
type: "android.emulator",
device: {
avdName: "Pixel_6_Pro_API_33",
avdName: emulator,
},
},
},
@@ -1,4 +1,4 @@
import { by, device, element, expect } from "detox";
import { device } from "detox";
import * as path from "path";
import { createCapture } from "../lib";
@@ -6,7 +6,10 @@ import { createCapture } from "../lib";
const projectRoot = path.resolve(__dirname, "../../");
// https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html
const languages = ["en-US", "nl-NL", "zh-CN"];
const languages = [
"en-US",
// "nl-NL", "zh-CN"
];
for (const locale of languages) {
const { captureAsync, resetAppAsync } = createCapture({
@@ -21,18 +24,8 @@ for (const locale of languages) {
await device.reloadReactNative();
});
it("should have welcome screen", async () => {
await expect(element(by.id("welcome"))).toBeVisible();
await captureAsync();
});
xit("should show hello screen after tap", async () => {
await element(by.id("hello_button")).tap();
await captureAsync();
});
xit("should show world screen after tap", async () => {
await element(by.id("world_button")).tap();
it("should load app", async () => {
// await expect(element(by.id("welcome"))).toBeVisible();
await captureAsync();
});
});
+23
View File
@@ -0,0 +1,23 @@
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;
+3 -6
View File
@@ -1,14 +1,11 @@
module.exports = {
testEnvironment: require.resolve("./environment.js"),
testRunner: require.resolve("jest-circus/runner"),
testTimeout: 120000,
rootDir: "..",
testMatch: ["<rootDir>/**/__tests__/*"],
testRegex: "/__tests__/.*(e2e)\\.[jt]sx?$",
transform: {
"^.+\\.[jt]sx?$": "ts-jest",
},
reporters: [require.resolve("detox/runners/jest/reporter")],
globalSetup: "detox/runners/jest/globalSetup",
globalTeardown: "detox/runners/jest/globalTeardown",
testEnvironment: "detox/runners/jest/testEnvironment",
reporters: [require.resolve("detox/runners/jest/streamlineReporter")],
verbose: true,
};
+16 -6
View File
@@ -4,10 +4,19 @@ import * as path from "path";
import { setStatusBar } from "./setStatusBar";
export function getOutputDir(projectRoot: string, locale: string) {
return path.resolve(
projectRoot,
`meta/screenshots/${device.getPlatform()}/${locale}/`
);
const store = device.getPlatform() === "ios" ? "apple" : "google";
return path.resolve(projectRoot, `merch/${store}/preview/${locale}/`);
}
function resolveName(str: string) {
if (str && device.getPlatform() === "ios" && typeof str === "string") {
// Convert a name like: `E9EA2214-6B88-4223-9872-8232168088FB {"type":"iPhone 12 Pro Max"}`
// to `iPhone 12 Pro Max`
// Name is important for screenshot sorting
const match = str.match(/"type"\s?:\s?"(.*)"}/i)?.[1];
return match || str;
}
return str;
}
export async function takeScreenshotAsync({
@@ -27,8 +36,9 @@ export async function takeScreenshotAsync({
if (index == null) {
index = fs.readdirSync(outputDir).length;
}
const deviceName = resolveName(device.name);
const name = `APP_${device.name}_${index}`.toUpperCase();
const name = `APP_${deviceName}-${index}`;
const imgPath = path.resolve(outputDir, `${name}.png`);
const imagePath = await device.takeScreenshot(name);
await fs.promises.copyFile(imagePath, imgPath);
@@ -58,7 +68,7 @@ export function createCapture({
clearAsync,
async resetAppAsync() {
// Clear old screen shots
await clearAsync();
// await clearAsync();
// configure status bars
setStatusBar();
+1
View File
@@ -1,3 +1,4 @@
import "react-native-gesture-handler";
import { registerRootComponent } from "expo";
import Constants from "expo-constants";
Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

+6
View File
@@ -0,0 +1,6 @@
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require("@expo/metro-config");
const config = getDefaultConfig(__dirname);
module.exports = config;
+29 -22
View File
@@ -3,6 +3,7 @@
"main": "./index.js",
"version": "1.0.0",
"scripts": {
"detox:clean": "detox clean-framework-cache && detox build-framework-cache",
"build:ios": "detox build -c ios.sim.debug",
"test:ios": "detox test -c ios.sim.debug",
"e2e:ios": "npm run build:ios && npm run test:ios",
@@ -13,7 +14,7 @@
"test:android": "detox test -c android.emu.debug",
"e2e:android": "npm run build:android && npm run test:android",
"build:android-release": "detox build -c android.emu.release",
"test:android-release": "detox test -c android.emu.release",
"test:android-release": "detox test -c android.emu.release --headless",
"e2e:android-release": "npm run build:android-release && npm run test:android-release",
"clean:android": "pushd android && ./gradlew clean && popd",
"start": "expo start --dev-client",
@@ -21,32 +22,38 @@
"android": "expo run:android"
},
"dependencies": {
"@config-plugins/android-jsc-intl": "*",
"@config-plugins/detox": "*",
"@config-plugins/react-native-adjust": "*",
"@config-plugins/react-native-callkeep": "*",
"detox": "^20.37.0",
"expo": "~53",
"expo-localization": "~16.1.5",
"expo-splash-screen": "~0.30.7",
"fbjs": "^0.8.18",
"@config-plugins/detox": "^1.0.0",
"expo": "^43.0.0",
"expo-localization": "~11.0.0",
"expo-splash-screen": "~0.13.5",
"expo-status-bar": "~1.1.0",
"expo-updates": "~0.10.13",
"ffmpeg-kit-react-native": "^4.5.0",
"i18n-js": "^3.8.0",
"luxon": "^1.27.0",
"react": "19.0.0",
"react-native": "0.79.2",
"react-native-adjust": "^5.1.0",
"react-native-callkeep": "^4.3.16",
"react-native-safe-area-context": "5.3.0"
"react": "17.0.1",
"react-native": "0.64.3",
"react-native-reanimated": "~2.2.0",
"react-native-safe-area-context": "3.3.2",
"react-native-screens": "~3.8.0",
"react-dom": "17.0.1",
"react-native-gesture-handler": "~1.10.2",
"react-native-web": "0.17.1"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/plugin-syntax-jsx": "^7.16.0",
"@types/jest": "^29.4.0",
"@expo/metro-config": "~0.3.0",
"@expo/xcpretty": "^4.1.0",
"@types/jest": "^26.0.19",
"@types/luxon": "^1.27.1",
"babel-jest": "^29.5.0",
"jest": "~29.7.0",
"jest-circus": "^29.5.0",
"ts-jest": "^29.0.5",
"typescript": "~5.8.3"
"@types/react": "~17.0.21",
"@types/react-native": "~0.64.12",
"babel-jest": "~25.2.6",
"detox": "^19.1.0",
"jest": "^26.5.0",
"jest-circus": "^26.5.2",
"ts-jest": "^26.4.4",
"typescript": "~4.3.5"
},
"private": true
}
+1 -1
View File
@@ -9,7 +9,7 @@ set -eu
iosName=$1
# Debug or Release
configuration=${3:-"Debug"}
configuration=$2
# YES or NO
UseModernBuildSystem=${3:-"NO"}
+1 -1
View File
@@ -16,7 +16,7 @@ else
commandFile=$(dirname "$0")/start.command
cat > ${commandFile} << EOF
cd "\$(dirname "\$0")/.."
# Run 'npx expo start --help' to get more parameters
# Run 'react-native start --help' to get more parameters
yarn start --port ${port}
EOF
# execute the file in a new command line window
@@ -0,0 +1,41 @@
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>
);
}
-27
View File
@@ -1,27 +0,0 @@
import React from "react";
import { SafeAreaView, Text, StyleSheet } from "react-native";
import { Adjust, AdjustConfig } from "react-native-adjust";
export default function App() {
React.useEffect(() => {
const adjustConfig = new AdjustConfig(
"APP_TOKEN",
AdjustConfig.EnvironmentSandbox
);
Adjust.enable();
}, []);
return (
<SafeAreaView style={styles.container}>
<Text>Adjust SDK</Text>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
});
+32
View File
@@ -0,0 +1,32 @@
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>
)
}
@@ -0,0 +1,70 @@
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;
@@ -0,0 +1,142 @@
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,87 @@
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>
);
}
+41
View File
@@ -0,0 +1,41 @@
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",
},
});
@@ -0,0 +1,58 @@
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;
+66
View File
@@ -0,0 +1,66 @@
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;
+3
View File
@@ -0,0 +1,3 @@
const { createWebpackConfigAsync } = require("expo-yarn-workspaces/webpack");
module.exports = createWebpackConfigAsync;
-123
View File
@@ -1,123 +0,0 @@
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;
};
-8
View File
@@ -1,8 +0,0 @@
{
"expo": {
"name": "apple-settings",
"icon": "https://github.com/expo.png",
"platforms": ["ios"],
"plugins": [["expo-build-properties", { "ios": { "ccacheEnabled": true } }]]
}
}
-5
View File
@@ -1,5 +0,0 @@
import { registerRootComponent } from "expo";
import App from "./src/App";
registerRootComponent(App);
-20
View File
@@ -1,20 +0,0 @@
{
"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
}
-57
View File
@@ -1,57 +0,0 @@
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;
-91
View File
@@ -1,91 +0,0 @@
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} />;
}
-4
View File
@@ -1,4 +0,0 @@
{
"compilerOptions": {},
"extends": "expo/tsconfig.base"
}
@@ -1,16 +0,0 @@
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;
};
-17
View File
@@ -1,17 +0,0 @@
{
"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"
}
]
]
}
}
-5
View File
@@ -1,5 +0,0 @@
import { registerRootComponent } from "expo";
import App from "./src/App";
registerRootComponent(App);
-19
View File
@@ -1,19 +0,0 @@
{
"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
}
-54
View File
@@ -1,54 +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://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>
);
}
@@ -1,4 +0,0 @@
{
"compilerOptions": {},
"extends": "expo/tsconfig.base"
}
-16
View File
@@ -1,16 +0,0 @@
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;
};
-32
View File
@@ -1,32 +0,0 @@
{
"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 } }]
]
}
}
-5
View File
@@ -1,5 +0,0 @@
import { registerRootComponent } from "expo";
import App from "./src/App";
registerRootComponent(App);
-19
View File
@@ -1,19 +0,0 @@
{
"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
}
-9
View File
@@ -1,9 +0,0 @@
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>
);
}
-16
View File
@@ -1,16 +0,0 @@
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;
};
-27
View File
@@ -1,27 +0,0 @@
{
"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 } }]
]
}
}
-5
View File
@@ -1,5 +0,0 @@
import { registerRootComponent } from "expo";
import App from "./src/App";
registerRootComponent(App);
-19
View File
@@ -1,19 +0,0 @@
{
"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
}
-9
View File
@@ -1,9 +0,0 @@
import { Text, View } from "react-native";
export default function App() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Branch</Text>
</View>
);
}
@@ -1,16 +0,0 @@
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;
};
@@ -1,23 +0,0 @@
{
"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 } }]
]
}
}
-5
View File
@@ -1,5 +0,0 @@
import { registerRootComponent } from "expo";
import App from "./src/App";
registerRootComponent(App);
@@ -1,19 +0,0 @@
{
"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
}
-159
View File
@@ -1,159 +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,4 +0,0 @@
{
"compilerOptions": {},
"extends": "expo/tsconfig.base"
}
-16
View File
@@ -1,16 +0,0 @@
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;
};
-14
View File
@@ -1,14 +0,0 @@
{
"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 } }]
]
}
}
-5
View File
@@ -1,5 +0,0 @@
import { registerRootComponent } from "expo";
import App from "./src/App";
registerRootComponent(App);
-21
View File
@@ -1,21 +0,0 @@
{
"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
}
Loaded 100 of 366 files, more files were not shown because too many files have changed in this diff. Show more