Please note that this class is used ONLY if you opt-in for the New Architecture (see the
16 | * `newArchEnabled` property). Is ignored otherwise.
17 | */
18 | public class MainApplicationTurboModuleManagerDelegate
19 | extends ReactPackageTurboModuleManagerDelegate {
20 |
21 | private static volatile boolean sIsSoLibraryLoaded;
22 |
23 | protected MainApplicationTurboModuleManagerDelegate(
24 | ReactApplicationContext reactApplicationContext, List packages) {
25 | super(reactApplicationContext, packages);
26 | }
27 |
28 | protected native HybridData initHybrid();
29 |
30 | native boolean canCreateTurboModule(String moduleName);
31 |
32 | public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
33 | protected MainApplicationTurboModuleManagerDelegate build(
34 | ReactApplicationContext context, List packages) {
35 | return new MainApplicationTurboModuleManagerDelegate(context, packages);
36 | }
37 | }
38 |
39 | @Override
40 | protected synchronized void maybeLoadOtherSoLibraries() {
41 | if (!sIsSoLibraryLoaded) {
42 | // If you change the name of your application .so file in the Android.mk file,
43 | // make sure you update the name here as well.
44 | SoLoader.loadLibrary("mobile_appmodules");
45 | sIsSoLibraryLoaded = true;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/android/app/src/main/jni/MainComponentsRegistry.cpp:
--------------------------------------------------------------------------------
1 | #include "MainComponentsRegistry.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | namespace facebook {
9 | namespace react {
10 |
11 | MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}
12 |
13 | std::shared_ptr
14 | MainComponentsRegistry::sharedProviderRegistry() {
15 | auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
16 |
17 | // Custom Fabric Components go here. You can register custom
18 | // components coming from your App or from 3rd party libraries here.
19 | //
20 | // providerRegistry->add(concreteComponentDescriptorProvider<
21 | // AocViewerComponentDescriptor>());
22 | return providerRegistry;
23 | }
24 |
25 | jni::local_ref
26 | MainComponentsRegistry::initHybrid(
27 | jni::alias_ref,
28 | ComponentFactory *delegate) {
29 | auto instance = makeCxxInstance(delegate);
30 |
31 | auto buildRegistryFunction =
32 | [](EventDispatcher::Weak const &eventDispatcher,
33 | ContextContainer::Shared const &contextContainer)
34 | -> ComponentDescriptorRegistry::Shared {
35 | auto registry = MainComponentsRegistry::sharedProviderRegistry()
36 | ->createComponentDescriptorRegistry(
37 | {eventDispatcher, contextContainer});
38 |
39 | auto mutableRegistry =
40 | std::const_pointer_cast(registry);
41 |
42 | mutableRegistry->setFallbackComponentDescriptor(
43 | std::make_shared(
44 | ComponentDescriptorParameters{
45 | eventDispatcher, contextContainer, nullptr}));
46 |
47 | return registry;
48 | };
49 |
50 | delegate->buildRegistryFunction = buildRegistryFunction;
51 | return instance;
52 | }
53 |
54 | void MainComponentsRegistry::registerNatives() {
55 | registerHybrid({
56 | makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid),
57 | });
58 | }
59 |
60 | } // namespace react
61 | } // namespace facebook
62 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | # AndroidX package structure to make it clearer which packages are bundled with the
21 | # Android operating system, and which are packaged with your app's APK
22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
23 | android.useAndroidX=true
24 |
25 | # Automatically convert third-party libraries to use AndroidX
26 | android.enableJetifier=true
27 |
28 | # Version of flipper SDK to use with React Native
29 |
30 | # Use this property to specify which architecture you want to build.
31 | # You can also override it from the CLI using
32 | # ./gradlew -PreactNativeArchitectures=x86_64
33 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
34 |
35 | # Use this property to enable support to the new architecture.
36 | # This will allow you to use TurboModules and the Fabric render in
37 | # your application. You should enable this flag either if you want
38 | # to write custom TurboModules/Fabric components OR use libraries that
39 | # are providing them.
40 | newArchEnabled=false
41 |
42 | # The hosted JavaScript engine
43 | # Supported values: expo.jsEngine = "hermes" | "jsc"
44 | expo.jsEngine=jsc
45 |
46 | # Enable GIF support in React Native images (~200 B increase)
47 | expo.gif.enabled=true
48 | # Enable webp support in React Native images (~85 KB increase)
49 | expo.webp.enabled=true
50 | # Enable animated webp support (~3.4 MB increase)
51 | # Disabled by default because iOS doesn't support animated webp
52 | expo.webp.animated=false
53 |
54 | FLIPPER_VERSION=0.125.0
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "resonate-mobile",
3 | "version": "1.0.0",
4 | "scripts": {
5 | "start": "expo start --dev-client",
6 | "android": "expo run:android",
7 | "expo:prebuild": "expo prebuild",
8 | "eslint:check": "eslint . --ext .jsx,.js,.ts,.tsx",
9 | "prettier:check": "prettier --check '**/*.{js,ts,jsx,tsx}'",
10 | "eslint:fix": "eslint --fix . --ext .jsx,.js,.ts,.tsx",
11 | "prettier:fix": "prettier --write '**/*.{js,ts,jsx,tsx}'",
12 | "lint": "npm run eslint:check && npm run prettier:check",
13 | "lint:fix": "npm run eslint:fix && npm run prettier:fix",
14 | "ios": "expo run:ios",
15 | "web": "expo start --web",
16 | "eject": "expo eject",
17 | "prepare": "husky install",
18 | "test:watch": "jest --watch --coverage=false --changedSince=origin/main",
19 | "test": "jest"
20 | },
21 | "dependencies": {
22 | "@react-native-community/slider": "4.2.3",
23 | "@react-navigation/material-bottom-tabs": "^6.2.4",
24 | "@react-navigation/native": "^6.0.13",
25 | "@tanstack/react-query": "^4.13.5",
26 | "dotenv": "^16.0.3",
27 | "expo": "~46.0.17",
28 | "expo-av": "~12.0.4",
29 | "expo-community-flipper": "^46.0.2",
30 | "expo-dev-client": "~1.3.1",
31 | "expo-splash-screen": "~0.16.2",
32 | "expo-status-bar": "~1.4.0",
33 | "expo-system-ui": "~1.3.0",
34 | "jest": "^26.6.3",
35 | "jest-expo": "^47.0.1",
36 | "lodash": "^4.17.21",
37 | "react": "18.0.0",
38 | "react-dom": "18.0.0",
39 | "react-native": "0.69.6",
40 | "react-native-flipper": "^0.173.0",
41 | "react-native-paper": "5.0.0-rc.10",
42 | "react-native-safe-area-context": "4.3.1",
43 | "react-native-screens": "~3.15.0",
44 | "react-native-web": "~0.18.7"
45 | },
46 | "devDependencies": {
47 | "@babel/core": "^7.18.6",
48 | "@commitlint/cli": "^17.2.0",
49 | "@commitlint/config-conventional": "^17.2.0",
50 | "@expo/cli": "^0.4.8",
51 | "@jest/types": "^29.3.1",
52 | "@testing-library/jest-native": "^5.2.0",
53 | "@testing-library/react-native": "^11.4.0",
54 | "@types/jest": "^29.2.2",
55 | "@types/lodash": "^4.14.184",
56 | "@types/react-dom": "^18.0.8",
57 | "@types/react-native": "^0.70.6",
58 | "eslint": "^8.26.0",
59 | "eslint-config-universe": "^11.1.0",
60 | "husky": ">=7",
61 | "lint-staged": ">=10",
62 | "prettier": "^2.7.1",
63 | "ts-node": "^10.9.1",
64 | "typescript": "^4.6.3"
65 | },
66 | "private": true,
67 | "lint-staged": {
68 | "*.js": "eslint --cache --fix",
69 | "*.{js,css,md}": "prettier --write"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
2 | require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
3 | require File.join(File.dirname(`node --print "require.resolve('@react-native-community/cli-platform-ios/package.json')"`), "native_modules")
4 |
5 | require 'json'
6 | podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
7 |
8 | platform :ios, podfile_properties['ios.deploymentTarget'] || '12.4'
9 | install! 'cocoapods',
10 | :deterministic_uuids => false
11 |
12 | target 'mobile' do
13 | use_expo_modules!
14 | config = use_native_modules!
15 |
16 | use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
17 |
18 | # Flags change depending on the env values.
19 | flags = get_default_flags()
20 |
21 | use_react_native!(
22 | :path => config[:reactNativePath],
23 | # @generated begin expo-community-flipper-isprod - expo prebuild (DO NOT MODIFY) sync-828c22a1a38236bf5b7c203393f474bc68356b34
24 | # ENV value added to support Hermes
25 | :production => ENV["PRODUCTION"] == "1" ? true : false,
26 | # @generated end expo-community-flipper-isprod
27 | :hermes_enabled => flags[:hermes_enabled] || podfile_properties['expo.jsEngine'] == 'hermes',
28 | :fabric_enabled => flags[:fabric_enabled],
29 | # @generated begin expo-community-flipper-urn - expo prebuild (DO NOT MODIFY) sync-2c72a3e830aecfd65d973c105092ad560f1397e6
30 | # Flipper arguments generated from app.json
31 | :flipper_configuration => ENV['FLIPPER_DISABLE'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled,
32 | # @generated end expo-community-flipper-urn
33 | # An absolute path to your application root.
34 | :app_path => "#{Dir.pwd}/.."
35 | )
36 |
37 | # Uncomment to opt-in to using Flipper
38 | # Note that if you have use_frameworks! enabled, Flipper will not work
39 | #
40 | # if !ENV['CI']
41 | # use_flipper!()
42 | # end
43 |
44 | post_install do |installer|
45 | react_native_post_install(installer)
46 | __apply_Xcode_12_5_M1_post_install_workaround(installer)
47 |
48 | # This is necessary for Xcode 14, because it signs resource bundles by default
49 | # when building for devices.
50 | installer.target_installation_results.pod_target_installation_results
51 | .each do |pod_name, target_installation_result|
52 | target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
53 | resource_bundle_target.build_configurations.each do |config|
54 | config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
55 | end
56 | end
57 | end
58 | end
59 |
60 | post_integrate do |installer|
61 | begin
62 | expo_patch_react_imports!(installer)
63 | rescue => e
64 | Pod::UI.warn e
65 | end
66 | end
67 | end
68 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | import org.apache.tools.ant.taskdefs.condition.Os
2 |
3 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
4 | buildscript {
5 | ext {
6 | buildToolsVersion = findProperty('android.buildToolsVersion') ?: '31.0.0'
7 | minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21')
8 | compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '31')
9 | targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '31')
10 | if (findProperty('android.kotlinVersion')) {
11 | kotlinVersion = findProperty('android.kotlinVersion')
12 | }
13 | frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0'
14 |
15 | if (System.properties['os.arch'] == 'aarch64') {
16 | // For M1 Users we need to use the NDK 24 which added support for aarch64
17 | ndkVersion = '24.0.8215888'
18 | } else {
19 | // Otherwise we default to the side-by-side NDK version from AGP.
20 | ndkVersion = '21.4.7075529'
21 | }
22 | }
23 | repositories {
24 | google()
25 | mavenCentral()
26 | }
27 | dependencies {
28 | classpath('com.android.tools.build:gradle:7.1.1')
29 | classpath('com.facebook.react:react-native-gradle-plugin')
30 | classpath('de.undercouch:gradle-download-task:5.0.1')
31 | // NOTE: Do not place your application dependencies here; they belong
32 | // in the individual module build.gradle files
33 | }
34 | }
35 |
36 | def REACT_NATIVE_VERSION = new File(['node', '--print',"JSON.parse(require('fs').readFileSync(require.resolve('react-native/package.json'), 'utf-8')).version"].execute(null, rootDir).text.trim())
37 |
38 | allprojects {
39 | configurations.all {
40 | resolutionStrategy {
41 | force "com.facebook.react:react-native:" + REACT_NATIVE_VERSION
42 | }
43 | }
44 |
45 | repositories {
46 | mavenLocal()
47 | maven {
48 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
49 | url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
50 | }
51 | maven {
52 | // Android JSC is installed from npm
53 | url(new File(['node', '--print', "require.resolve('jsc-android/package.json')"].execute(null, rootDir).text.trim(), '../dist'))
54 | }
55 |
56 | google()
57 | mavenCentral {
58 | // We don't want to fetch react-native from Maven Central as there are
59 | // older versions over there.
60 | content {
61 | excludeGroup 'com.facebook.react'
62 | }
63 | }
64 | maven { url 'https://www.jitpack.io' }
65 | }
66 | }
67 |
68 | configurations.all {
69 | resolutionStrategy {
70 | force 'com.facebook.react:react-native:0.69.6'
71 | }
72 | }
--------------------------------------------------------------------------------
/ios/mobile/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | mobile
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0.0
21 | CFBundleSignature
22 | ????
23 | CFBundleURLTypes
24 |
25 |
26 | CFBundleURLSchemes
27 |
28 | com.resonatecoop.mobile
29 |
30 |
31 |
32 | CFBundleURLSchemes
33 |
34 | exp+mobile
35 |
36 |
37 |
38 | CFBundleVersion
39 | 1
40 | LSRequiresIPhoneOS
41 |
42 | NSAppTransportSecurity
43 |
44 | NSAllowsArbitraryLoads
45 |
46 | NSExceptionDomains
47 |
48 | localhost
49 |
50 | NSExceptionAllowsInsecureHTTPLoads
51 |
52 |
53 |
54 |
55 | NSMicrophoneUsageDescription
56 | Allow $(PRODUCT_NAME) to access your microphone
57 | UIBackgroundModes
58 |
59 | audio
60 |
61 | UILaunchStoryboardName
62 | SplashScreen
63 | UIRequiredDeviceCapabilities
64 |
65 | armv7
66 |
67 | UIRequiresFullScreen
68 |
69 | UIStatusBarStyle
70 | UIStatusBarStyleDefault
71 | UISupportedInterfaceOrientations
72 |
73 | UIInterfaceOrientationPortrait
74 | UIInterfaceOrientationPortraitUpsideDown
75 |
76 | UISupportedInterfaceOrientations~ipad
77 |
78 | UIInterfaceOrientationPortrait
79 | UIInterfaceOrientationPortraitUpsideDown
80 | UIInterfaceOrientationLandscapeLeft
81 | UIInterfaceOrientationLandscapeRight
82 |
83 | UIUserInterfaceStyle
84 | Automatic
85 | UIViewControllerBasedStatusBarAppearance
86 |
87 |
88 |
--------------------------------------------------------------------------------
/ios/mobile/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "idiom": "iphone",
5 | "size": "20x20",
6 | "scale": "2x",
7 | "filename": "App-Icon-20x20@2x.png"
8 | },
9 | {
10 | "idiom": "iphone",
11 | "size": "20x20",
12 | "scale": "3x",
13 | "filename": "App-Icon-20x20@3x.png"
14 | },
15 | {
16 | "idiom": "iphone",
17 | "size": "29x29",
18 | "scale": "1x",
19 | "filename": "App-Icon-29x29@1x.png"
20 | },
21 | {
22 | "idiom": "iphone",
23 | "size": "29x29",
24 | "scale": "2x",
25 | "filename": "App-Icon-29x29@2x.png"
26 | },
27 | {
28 | "idiom": "iphone",
29 | "size": "29x29",
30 | "scale": "3x",
31 | "filename": "App-Icon-29x29@3x.png"
32 | },
33 | {
34 | "idiom": "iphone",
35 | "size": "40x40",
36 | "scale": "2x",
37 | "filename": "App-Icon-40x40@2x.png"
38 | },
39 | {
40 | "idiom": "iphone",
41 | "size": "40x40",
42 | "scale": "3x",
43 | "filename": "App-Icon-40x40@3x.png"
44 | },
45 | {
46 | "idiom": "iphone",
47 | "size": "60x60",
48 | "scale": "2x",
49 | "filename": "App-Icon-60x60@2x.png"
50 | },
51 | {
52 | "idiom": "iphone",
53 | "size": "60x60",
54 | "scale": "3x",
55 | "filename": "App-Icon-60x60@3x.png"
56 | },
57 | {
58 | "idiom": "ipad",
59 | "size": "20x20",
60 | "scale": "1x",
61 | "filename": "App-Icon-20x20@1x.png"
62 | },
63 | {
64 | "idiom": "ipad",
65 | "size": "20x20",
66 | "scale": "2x",
67 | "filename": "App-Icon-20x20@2x.png"
68 | },
69 | {
70 | "idiom": "ipad",
71 | "size": "29x29",
72 | "scale": "1x",
73 | "filename": "App-Icon-29x29@1x.png"
74 | },
75 | {
76 | "idiom": "ipad",
77 | "size": "29x29",
78 | "scale": "2x",
79 | "filename": "App-Icon-29x29@2x.png"
80 | },
81 | {
82 | "idiom": "ipad",
83 | "size": "40x40",
84 | "scale": "1x",
85 | "filename": "App-Icon-40x40@1x.png"
86 | },
87 | {
88 | "idiom": "ipad",
89 | "size": "40x40",
90 | "scale": "2x",
91 | "filename": "App-Icon-40x40@2x.png"
92 | },
93 | {
94 | "idiom": "ipad",
95 | "size": "76x76",
96 | "scale": "1x",
97 | "filename": "App-Icon-76x76@1x.png"
98 | },
99 | {
100 | "idiom": "ipad",
101 | "size": "76x76",
102 | "scale": "2x",
103 | "filename": "App-Icon-76x76@2x.png"
104 | },
105 | {
106 | "idiom": "ipad",
107 | "size": "83.5x83.5",
108 | "scale": "2x",
109 | "filename": "App-Icon-83.5x83.5@2x.png"
110 | },
111 | {
112 | "idiom": "ios-marketing",
113 | "size": "1024x1024",
114 | "scale": "1x",
115 | "filename": "ItunesArtwork@2x.png"
116 | }
117 | ],
118 | "info": {
119 | "version": 1,
120 | "author": "expo"
121 | }
122 | }
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/resonatecoop/mobile/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.resonatecoop.mobile;
2 |
3 | import android.os.Build;
4 | import android.os.Bundle;
5 |
6 | import com.facebook.react.ReactActivity;
7 | import com.facebook.react.ReactActivityDelegate;
8 | import com.facebook.react.ReactRootView;
9 |
10 | import expo.modules.ReactActivityDelegateWrapper;
11 |
12 | public class MainActivity extends ReactActivity {
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | // Set the theme to AppTheme BEFORE onCreate to support
16 | // coloring the background, status bar, and navigation bar.
17 | // This is required for expo-splash-screen.
18 | setTheme(R.style.AppTheme);
19 | super.onCreate(null);
20 | }
21 |
22 | /**
23 | * Returns the name of the main component registered from JavaScript.
24 | * This is used to schedule rendering of the component.
25 | */
26 | @Override
27 | protected String getMainComponentName() {
28 | return "main";
29 | }
30 |
31 | /**
32 | * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
33 | * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
34 | * (Paper).
35 | */
36 | @Override
37 | protected ReactActivityDelegate createReactActivityDelegate() {
38 | return new ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
39 | new MainActivityDelegate(this, getMainComponentName())
40 | );
41 | }
42 |
43 | /**
44 | * Align the back button behavior with Android S
45 | * where moving root activities to background instead of finishing activities.
46 | * @see onBackPressed
47 | */
48 | @Override
49 | public void invokeDefaultOnBackPressed() {
50 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
51 | if (!moveTaskToBack(false)) {
52 | // For non-root activities, use the default implementation to finish them.
53 | super.invokeDefaultOnBackPressed();
54 | }
55 | return;
56 | }
57 |
58 | // Use the default back button implementation on Android S
59 | // because it's doing more than {@link Activity#moveTaskToBack} in fact.
60 | super.invokeDefaultOnBackPressed();
61 | }
62 |
63 | public static class MainActivityDelegate extends ReactActivityDelegate {
64 | public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
65 | super(activity, mainComponentName);
66 | }
67 |
68 | @Override
69 | protected ReactRootView createRootView() {
70 | ReactRootView reactRootView = new ReactRootView(getContext());
71 | // If you opted-in for the New Architecture, we enable the Fabric Renderer.
72 | reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
73 | return reactRootView;
74 | }
75 |
76 | @Override
77 | protected boolean isConcurrentRootEnabled() {
78 | // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
79 | // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
80 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/android/app/src/debug/java/com/resonatecoop/mobile/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | *
This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package com.resonatecoop.mobile;
8 |
9 | import android.content.Context;
10 | import com.facebook.flipper.android.AndroidFlipperClient;
11 | import com.facebook.flipper.android.utils.FlipperUtils;
12 | import com.facebook.flipper.core.FlipperClient;
13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping;
17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
20 | import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
22 | import com.facebook.react.ReactInstanceManager;
23 | import com.facebook.react.bridge.ReactContext;
24 | import com.facebook.react.modules.network.NetworkingModule;
25 | import okhttp3.OkHttpClient;
26 |
27 | public class ReactNativeFlipper {
28 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
29 | if (FlipperUtils.shouldEnableFlipper(context)) {
30 | final FlipperClient client = AndroidFlipperClient.getInstance(context);
31 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
32 | client.addPlugin(new ReactFlipperPlugin());
33 | client.addPlugin(new DatabasesFlipperPlugin(context));
34 | client.addPlugin(new SharedPreferencesFlipperPlugin(context));
35 | client.addPlugin(CrashReporterPlugin.getInstance());
36 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
37 | NetworkingModule.setCustomClientBuilder(
38 | new NetworkingModule.CustomClientBuilder() {
39 | @Override
40 | public void apply(OkHttpClient.Builder builder) {
41 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
42 | }
43 | });
44 | client.addPlugin(networkFlipperPlugin);
45 | client.start();
46 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
47 | // Hence we run if after all native modules have been initialized
48 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
49 | if (reactContext == null) {
50 | reactInstanceManager.addReactInstanceEventListener(
51 | new ReactInstanceManager.ReactInstanceEventListener() {
52 | @Override
53 | public void onReactContextInitialized(ReactContext reactContext) {
54 | reactInstanceManager.removeReactInstanceEventListener(this);
55 | reactContext.runOnNativeModulesQueueThread(
56 | new Runnable() {
57 | @Override
58 | public void run() {
59 | client.addPlugin(new FrescoFlipperPlugin());
60 | }
61 | });
62 | }
63 | });
64 | } else {
65 | client.addPlugin(new FrescoFlipperPlugin());
66 | }
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/ios/mobile.xcodeproj/xcshareddata/xcschemes/mobile.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/resonatecoop/mobile/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.resonatecoop.mobile;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.content.res.Configuration;
6 | import androidx.annotation.NonNull;
7 |
8 | import com.facebook.react.PackageList;
9 | import com.facebook.react.ReactApplication;
10 | import com.facebook.react.ReactInstanceManager;
11 | import com.facebook.react.ReactNativeHost;
12 | import com.facebook.react.ReactPackage;
13 | import com.facebook.react.config.ReactFeatureFlags;
14 | import com.facebook.soloader.SoLoader;
15 | import com.resonatecoop.mobile.newarchitecture.MainApplicationReactNativeHost;
16 |
17 | import expo.modules.ApplicationLifecycleDispatcher;
18 | import expo.modules.ReactNativeHostWrapper;
19 |
20 | import java.lang.reflect.InvocationTargetException;
21 | import java.util.List;
22 |
23 | public class MainApplication extends Application implements ReactApplication {
24 | private final ReactNativeHost mReactNativeHost = new ReactNativeHostWrapper(
25 | this,
26 | new ReactNativeHost(this) {
27 | @Override
28 | public boolean getUseDeveloperSupport() {
29 | return BuildConfig.DEBUG;
30 | }
31 |
32 | @Override
33 | protected List getPackages() {
34 | @SuppressWarnings("UnnecessaryLocalVariable")
35 | List packages = new PackageList(this).getPackages();
36 | // Packages that cannot be autolinked yet can be added manually here, for example:
37 | // packages.add(new MyReactNativePackage());
38 | return packages;
39 | }
40 |
41 | @Override
42 | protected String getJSMainModuleName() {
43 | return "index";
44 | }
45 | });
46 |
47 | private final ReactNativeHost mNewArchitectureNativeHost =
48 | new ReactNativeHostWrapper(this, new MainApplicationReactNativeHost(this));
49 |
50 | @Override
51 | public ReactNativeHost getReactNativeHost() {
52 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
53 | return mNewArchitectureNativeHost;
54 | } else {
55 | return mReactNativeHost;
56 | }
57 | }
58 |
59 | @Override
60 | public void onCreate() {
61 | super.onCreate();
62 | // If you opted-in for the New Architecture, we enable the TurboModule system
63 | ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
64 | SoLoader.init(this, /* native exopackage */ false);
65 |
66 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
67 | ApplicationLifecycleDispatcher.onApplicationCreate(this);
68 | }
69 |
70 | @Override
71 | public void onConfigurationChanged(@NonNull Configuration newConfig) {
72 | super.onConfigurationChanged(newConfig);
73 | ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig);
74 | }
75 |
76 | /**
77 | * Loads Flipper in React Native templates. Call this in the onCreate method with something like
78 | * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
79 | *
80 | * @param context
81 | * @param reactInstanceManager
82 | */
83 | private static void initializeFlipper(
84 | Context context, ReactInstanceManager reactInstanceManager) {
85 | if (BuildConfig.DEBUG) {
86 | try {
87 | /*
88 | We use reflection here to pick up the class that initializes Flipper,
89 | since Flipper library is not available in release mode
90 | */
91 | Class> aClass = Class.forName("com.resonatecoop.mobile.ReactNativeFlipper");
92 | aClass
93 | .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
94 | .invoke(null, context, reactInstanceManager);
95 | } catch (ClassNotFoundException e) {
96 | e.printStackTrace();
97 | } catch (NoSuchMethodException e) {
98 | e.printStackTrace();
99 | } catch (IllegalAccessException e) {
100 | e.printStackTrace();
101 | } catch (InvocationTargetException e) {
102 | e.printStackTrace();
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/client/api/fetch-client.ts:
--------------------------------------------------------------------------------
1 | import { FetchError } from "./error";
2 | import fetchWithTimeout, { FetchOptions } from "./fetch-with-timeout";
3 |
4 | interface ServiceClientOptions {
5 | baseURL?: string;
6 | headers?: Record;
7 | timeout?: number;
8 | }
9 |
10 | export class FetchClient {
11 | options: ServiceClientOptions;
12 | constructor(options: ServiceClientOptions) {
13 | this.options = options;
14 | }
15 |
16 | mergeOptions(options?: ServiceClientOptions): ServiceClientOptions {
17 | return {
18 | ...this.options,
19 | ...options,
20 | headers: this.mergeHeaders(options?.headers),
21 | };
22 | }
23 |
24 | mergeHeaders(newHeaders: Record = {}) {
25 | const headers = { ...this.options.headers };
26 | for (const key of Object.keys(newHeaders)) {
27 | const value = newHeaders[key];
28 | if (value === undefined) {
29 | delete headers[key];
30 | } else {
31 | headers[key] = value;
32 | }
33 | }
34 | return headers;
35 | }
36 |
37 | setOptions(options?: ServiceClientOptions) {
38 | this.options = this.mergeOptions(options);
39 | }
40 |
41 | extend(options: ServiceClientOptions) {
42 | return new FetchClient(this.mergeOptions(options));
43 | }
44 |
45 | getURL(endpoint: string, prefix: string) {
46 | const result = new URL(endpoint, prefix);
47 | return result.toString();
48 | }
49 |
50 | request(
51 | _method: string,
52 | endpoint: string,
53 | body?: BodyInit,
54 | options?: ServiceClientOptions
55 | ) {
56 | const { baseURL, headers, timeout = 0 } = this.mergeOptions(options);
57 | const url = this.getURL(endpoint, baseURL || "");
58 | const method = _method.toUpperCase();
59 | const opts: FetchOptions = {
60 | method,
61 | headers,
62 | timeout,
63 | };
64 |
65 | // fetch will throw if given body for these
66 | if (method !== "GET" && method !== "HEAD") {
67 | opts.body = body;
68 | }
69 |
70 | return fetchWithTimeout(url, opts);
71 | }
72 |
73 | json(
74 | method: string,
75 | endpoint: string,
76 | payload: U | undefined,
77 | options: Partial = { headers: {} }
78 | ) {
79 | if (!options.headers) {
80 | options.headers = {};
81 | }
82 |
83 | options.headers["Content-Type"] = "application/json";
84 | options.headers["Accept"] = "application/json";
85 |
86 | return this.request(
87 | method,
88 | endpoint,
89 | JSON.stringify(payload),
90 | options
91 | ).then((res) => (res.status === 204 ? (null as T) : parseJSON(res)));
92 | }
93 |
94 | put(
95 | endpoint: string,
96 | payload?: U,
97 | options?: ServiceClientOptions
98 | ) {
99 | return this.json("PUT", endpoint, payload, options);
100 | }
101 |
102 | post(
103 | endpoint: string,
104 | payload?: U,
105 | options?: ServiceClientOptions
106 | ) {
107 | return this.json("POST", endpoint, payload, options);
108 | }
109 |
110 | patch(
111 | endpoint: string,
112 | payload?: U,
113 | options?: ServiceClientOptions
114 | ) {
115 | return this.json("PATCH", endpoint, payload, options);
116 | }
117 |
118 | get>(
119 | endpoint: string,
120 | params?: U,
121 | options?: ServiceClientOptions
122 | ) {
123 | if (params) {
124 | endpoint += "?" + new URLSearchParams(params).toString();
125 | }
126 | return this.json("GET", endpoint, {}, options);
127 | }
128 |
129 | submit(endpoint: string, body: BodyInit, options?: ServiceClientOptions) {
130 | return this.request("POST", endpoint, body, {
131 | ...options,
132 | headers: { "Content-Type": "application/x-www-form-urlencoded" },
133 | }).then(parseJSON);
134 | }
135 | }
136 |
137 | function parseJSON(res: Response) {
138 | return res.json().catch(() => {
139 | return Promise.reject(
140 | new FetchError("Failed to parse JSON payload", res.url, res)
141 | );
142 | });
143 | }
144 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > 🛠 **Status: Active Development | Experimental**
2 | >
3 | > This project is currently broken and under very active development.
4 |
5 | ## 🎵 Resonate Mobile
6 |
7 | A mobile app for playing music on [Resonate](https://stream.resonate.coop/), an open source music streaming co-op.
8 |
9 | This is a newer iteration, built completely in React Native and TypeScript, which aims to expand upon [`stream-app`](https://github.com/peterklingelhofer/stream-app), the initial [`react-native-webview`](https://github.com/react-native-webview/react-native-webview) implementation. Note that the [`stream-app`](https://github.com/peterklingelhofer/stream-app) is still being used on Google Play Store and Apple Stores, so please submit any issues for problems encountered [there](https://github.com/resonatecoop/stream-app/issues).
10 |
11 |
12 | ## 🎶 Description
13 |
14 | Resonate is an open-source music streaming service run by a cooperative of artists and software developers.
15 |
16 | If you want to know what we're building or want to get more involved, head over to the Platform category on our [forum](https://community.resonate.is/c/platform/l/latest?board=default) or read the [Developer Guide](https://community.resonate.is/docs?topic=2262) in our [Resonate Handbook](https://community.resonate.is/docs).
17 |
18 | View the [project board](https://github.com/resonatecoop/mobile/projects/1) where work is tracked for this repository. If you're looking for a good first task, feel encouraged to take on an un-assigned [`help wanted` or `good first task` issues](https://github.com/resonatecoop/mobile/issues).
19 |
20 | Are you building something using the Resonate [API](#api) and would like to request a change? Resonate welcomes #proposals in the [Co-Operation section of the forum](https://community.resonate.is/c/66).
21 |
22 |
23 | ## 🗂 Tech Stack
24 |
25 | - React Native
26 | - TypeScript
27 |
28 |
29 | ## 🔧 Installation & Start
30 |
31 | Clone this repository, install dependencies, and start expo.
32 |
33 | ```sh
34 | git clone https://github.com/resonatecoop/mobile.git
35 | cd mobile
36 | yarn
37 | expo start
38 | ```
39 |
40 | You can also use device-specific commands to run Expo on your preferred device:
41 | ```sh
42 | yarn run android
43 | yarn run ios
44 | yarn run web
45 | ```
46 |
47 | ## 🧪 Testing
48 | Expect your code contributions to be tested: we use [commitlint](https://commitlint.js.org) to lint commit messages, and [prettier](https://prettier.io) to lint code.
49 |
50 | To test the `dark` theme on Android Studio, use the following command. Please try to ensure your changes work with both `light` and `dark` themes:
51 |
52 | ```sh
53 | adb shell "cmd uimode night yes"
54 | ```
55 |
56 | ## 📚 Contributing
57 |
58 | Contributing to others’ projects is an avenue to learn new software development skills and experience new technologies. The pull request is how your personal contributions will be added to the project. The following is an overview of the Git project management workflow:
59 |
60 | Search project for contribution instructions and follow them if present.
61 | Fork project repo from your personal Github account.
62 | Copy the fork and clone repo onto your local machine.
63 | Add the original repository (the you forked) as a remote called upstream.
64 | If you created your fork a while ago be sure to pull upstream changes into your local repository.
65 | Create a new branch to work on! Branch from develop if it exists, else from master.
66 | Implement/fix your feature.
67 | Follow the code style of the project, including indentation.
68 | If the project has included tests use them.
69 | Add additional tests or convert existing tests as necessary.
70 | Add or convert project documentation as needed.
71 | Push your working branch to your forked repo on Github.
72 | Make a pull request from your forked repo to the origin master or development branch if present.
73 | Once your pull request is merged, pull down upstream master to your local repo and delete any additional branch(es) you may have created.
74 | Commit messages should be written in present tense describing what the committed code does and not what you changed in the code.
75 |
76 |
77 | ## 📖 References
78 |
79 | - [React Native](https://reactnative.dev/)
80 | - [TypeScript](https://typescriptlang.org/')
81 |
82 |
83 | ## 📑 License
84 |
85 | `mobile` is licensed under the
86 | [GNU General Public License v3.0](https://github.com/peterklingelhofer/stream-app/blob/master/LICENSE)
87 |
88 | Permissions of this strong copyleft license are conditioned on making available complete source code of licensed works and modifications, which include larger works using a licensed work, under the same license. Copyright and license notices must be preserved. Contributors provide an express grant of patent rights.
89 |
--------------------------------------------------------------------------------
/ios/mobile/SplashScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/resonatecoop/mobile/newarchitecture/MainApplicationReactNativeHost.java:
--------------------------------------------------------------------------------
1 | package com.resonatecoop.mobile.newarchitecture;
2 |
3 | import android.app.Application;
4 | import androidx.annotation.NonNull;
5 | import com.facebook.react.PackageList;
6 | import com.facebook.react.ReactInstanceManager;
7 | import com.facebook.react.ReactNativeHost;
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
10 | import com.facebook.react.bridge.JSIModulePackage;
11 | import com.facebook.react.bridge.JSIModuleProvider;
12 | import com.facebook.react.bridge.JSIModuleSpec;
13 | import com.facebook.react.bridge.JSIModuleType;
14 | import com.facebook.react.bridge.JavaScriptContextHolder;
15 | import com.facebook.react.bridge.ReactApplicationContext;
16 | import com.facebook.react.bridge.UIManager;
17 | import com.facebook.react.fabric.ComponentFactory;
18 | import com.facebook.react.fabric.CoreComponentsRegistry;
19 | import com.facebook.react.fabric.EmptyReactNativeConfig;
20 | import com.facebook.react.fabric.FabricJSIModuleProvider;
21 | import com.facebook.react.fabric.ReactNativeConfig;
22 | import com.facebook.react.uimanager.ViewManagerRegistry;
23 | import com.resonatecoop.mobile.BuildConfig;
24 | import com.resonatecoop.mobile.newarchitecture.components.MainComponentsRegistry;
25 | import com.resonatecoop.mobile.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
26 | import java.util.ArrayList;
27 | import java.util.List;
28 |
29 | /**
30 | * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
31 | * TurboModule delegates and the Fabric Renderer.
32 | *
33 | *
Please note that this class is used ONLY if you opt-in for the New Architecture (see the
34 | * `newArchEnabled` property). Is ignored otherwise.
35 | */
36 | public class MainApplicationReactNativeHost extends ReactNativeHost {
37 | public MainApplicationReactNativeHost(Application application) {
38 | super(application);
39 | }
40 |
41 | @Override
42 | public boolean getUseDeveloperSupport() {
43 | return BuildConfig.DEBUG;
44 | }
45 |
46 | @Override
47 | protected List getPackages() {
48 | List packages = new PackageList(this).getPackages();
49 | // Packages that cannot be autolinked yet can be added manually here, for example:
50 | // packages.add(new MyReactNativePackage());
51 | // TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
52 | // packages.add(new TurboReactPackage() { ... });
53 | // If you have custom Fabric Components, their ViewManagers should also be loaded here
54 | // inside a ReactPackage.
55 | return packages;
56 | }
57 |
58 | @Override
59 | protected String getJSMainModuleName() {
60 | return "index";
61 | }
62 |
63 | @NonNull
64 | @Override
65 | protected ReactPackageTurboModuleManagerDelegate.Builder
66 | getReactPackageTurboModuleManagerDelegateBuilder() {
67 | // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
68 | // for the new architecture and to use TurboModules correctly.
69 | return new MainApplicationTurboModuleManagerDelegate.Builder();
70 | }
71 |
72 | @Override
73 | protected JSIModulePackage getJSIModulePackage() {
74 | return new JSIModulePackage() {
75 | @Override
76 | public List getJSIModules(
77 | final ReactApplicationContext reactApplicationContext,
78 | final JavaScriptContextHolder jsContext) {
79 | final List specs = new ArrayList<>();
80 |
81 | // Here we provide a new JSIModuleSpec that will be responsible of providing the
82 | // custom Fabric Components.
83 | specs.add(
84 | new JSIModuleSpec() {
85 | @Override
86 | public JSIModuleType getJSIModuleType() {
87 | return JSIModuleType.UIManager;
88 | }
89 |
90 | @Override
91 | public JSIModuleProvider getJSIModuleProvider() {
92 | final ComponentFactory componentFactory = new ComponentFactory();
93 | CoreComponentsRegistry.register(componentFactory);
94 |
95 | // Here we register a Components Registry.
96 | // The one that is generated with the template contains no components
97 | // and just provides you the one from React Native core.
98 | MainComponentsRegistry.register(componentFactory);
99 |
100 | final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
101 |
102 | ViewManagerRegistry viewManagerRegistry =
103 | new ViewManagerRegistry(
104 | reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
105 |
106 | return new FabricJSIModuleProvider(
107 | reactApplicationContext,
108 | componentFactory,
109 | ReactNativeConfig.DEFAULT_CONFIG,
110 | viewManagerRegistry);
111 | }
112 | });
113 | return specs;
114 | }
115 | };
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | r7477cdv4@relay.firefox.com.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/client/theme/index.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | DarkTheme as NavigationDarkTheme,
3 | DefaultTheme as NavigationLightTheme,
4 | NavigationContainer,
5 | } from "@react-navigation/native";
6 | import merge from "lodash/merge";
7 | import {
8 | createContext,
9 | PropsWithChildren,
10 | useContext,
11 | useEffect,
12 | useMemo,
13 | useState,
14 | } from "react";
15 | import { Appearance } from "react-native";
16 | import {
17 | Provider as PaperProvider,
18 | adaptNavigationTheme,
19 | MD3DarkTheme,
20 | MD3LightTheme,
21 | } from "react-native-paper";
22 |
23 | export type ThemeMode = "light" | "dark";
24 |
25 | const { LightTheme, DarkTheme } = adaptNavigationTheme({
26 | light: NavigationLightTheme,
27 | dark: NavigationDarkTheme,
28 | });
29 |
30 | const lightTheme = merge({}, LightTheme, MD3LightTheme, {
31 | colors: {
32 | primary: "rgb(0, 101, 140)",
33 | onPrimary: "rgb(255, 255, 255)",
34 | primaryContainer: "rgb(197, 231, 255)",
35 | onPrimaryContainer: "rgb(0, 30, 45)",
36 | secondary: "rgb(78, 97, 109)",
37 | onSecondary: "rgb(255, 255, 255)",
38 | secondaryContainer: "rgb(210, 229, 244)",
39 | onSecondaryContainer: "rgb(10, 30, 40)",
40 | tertiary: "rgb(97, 89, 124)",
41 | onTertiary: "rgb(255, 255, 255)",
42 | tertiaryContainer: "rgb(231, 222, 255)",
43 | onTertiaryContainer: "rgb(29, 23, 53)",
44 | error: "rgb(186, 26, 26)",
45 | onError: "rgb(255, 255, 255)",
46 | errorContainer: "rgb(255, 218, 214)",
47 | onErrorContainer: "rgb(65, 0, 2)",
48 | background: "rgb(251, 252, 255)",
49 | onBackground: "rgb(25, 28, 30)",
50 | surface: "rgb(251, 252, 255)",
51 | onSurface: "rgb(25, 28, 30)",
52 | surfaceVariant: "rgb(221, 227, 234)",
53 | onSurfaceVariant: "rgb(65, 72, 77)",
54 | outline: "rgb(113, 120, 126)",
55 | outlineVariant: "rgb(193, 199, 206)",
56 | shadow: "rgb(0, 0, 0)",
57 | scrim: "rgb(0, 0, 0)",
58 | inverseSurface: "rgb(46, 49, 51)",
59 | inverseOnSurface: "rgb(240, 241, 243)",
60 | inversePrimary: "rgb(127, 208, 255)",
61 | elevation: {
62 | level0: "transparent",
63 | level1: "rgb(238, 244, 249)",
64 | level2: "rgb(231, 240, 246)",
65 | level3: "rgb(223, 235, 242)",
66 | level4: "rgb(221, 234, 241)",
67 | level5: "rgb(216, 231, 239)",
68 | },
69 | surfaceDisabled: "rgba(25, 28, 30, 0.12)",
70 | onSurfaceDisabled: "rgba(25, 28, 30, 0.38)",
71 | backdrop: "rgba(42, 49, 54, 0.4)",
72 | },
73 | });
74 | const darkTheme = merge({}, DarkTheme, MD3DarkTheme, {
75 | colors: {
76 | colors: {
77 | primary: "rgb(127, 208, 255)",
78 | onPrimary: "rgb(0, 52, 74)",
79 | primaryContainer: "rgb(0, 76, 106)",
80 | onPrimaryContainer: "rgb(197, 231, 255)",
81 | secondary: "rgb(182, 201, 216)",
82 | onSecondary: "rgb(32, 51, 62)",
83 | secondaryContainer: "rgb(55, 73, 85)",
84 | onSecondaryContainer: "rgb(210, 229, 244)",
85 | tertiary: "rgb(203, 193, 233)",
86 | onTertiary: "rgb(51, 44, 76)",
87 | tertiaryContainer: "rgb(73, 66, 99)",
88 | onTertiaryContainer: "rgb(231, 222, 255)",
89 | error: "rgb(255, 180, 171)",
90 | onError: "rgb(105, 0, 5)",
91 | errorContainer: "rgb(147, 0, 10)",
92 | onErrorContainer: "rgb(255, 180, 171)",
93 | background: "rgb(25, 28, 30)",
94 | onBackground: "rgb(225, 226, 229)",
95 | surface: "rgb(25, 28, 30)",
96 | onSurface: "rgb(225, 226, 229)",
97 | surfaceVariant: "rgb(65, 72, 77)",
98 | onSurfaceVariant: "rgb(193, 199, 206)",
99 | outline: "rgb(139, 146, 151)",
100 | outlineVariant: "rgb(65, 72, 77)",
101 | shadow: "rgb(0, 0, 0)",
102 | scrim: "rgb(0, 0, 0)",
103 | inverseSurface: "rgb(225, 226, 229)",
104 | inverseOnSurface: "rgb(46, 49, 51)",
105 | inversePrimary: "rgb(0, 101, 140)",
106 | elevation: {
107 | level0: "transparent",
108 | level1: "rgb(30, 37, 41)",
109 | level2: "rgb(33, 42, 48)",
110 | level3: "rgb(36, 48, 55)",
111 | level4: "rgb(37, 50, 57)",
112 | level5: "rgb(39, 53, 62)",
113 | },
114 | surfaceDisabled: "rgba(225, 226, 229, 0.12)",
115 | onSurfaceDisabled: "rgba(225, 226, 229, 0.38)",
116 | backdrop: "rgba(42, 49, 54, 0.4)",
117 | },
118 | },
119 | });
120 |
121 | export const themes = {
122 | light: lightTheme,
123 | dark: darkTheme,
124 | };
125 |
126 | const ThemeModeContext = createContext<{
127 | setMode: (mode: ThemeMode) => void;
128 | mode: ThemeMode;
129 | }>({
130 | setMode: (mode: ThemeMode) => {},
131 | mode: "dark",
132 | });
133 |
134 | export function ThemeModeProvider({ children }: PropsWithChildren